문제

Its probarbly a simple 3-tier problem. I just want to make sure we use the best practice for this and I am not that familiary with the structures yet.

We have the 3 tiers:

  • GUI: ASP.NET for Presentation-layer (first platform)
  • BAL: Business-layer will be handling the logic on a webserver in C#, so we both can use it for webforms/MVC + webservices
  • DAL: LINQ to SQL in the Data-layer, returning BusinessObjects not LINQ.
  • DB: The SQL will be Microsoft SQL-server/Express (havent decided yet).

Lets think of setup where we have a database of [Persons]. They can all have multiple [Address]es and we have a complete list of all [PostalCode] and corresponding citynames etc.

The deal is that we have joined a lot of details from other tables.

{Relations}/[tables]

  • [Person]:1 --- N:{PersonAddress}:M --- 1:[Address]
  • [Address]:N --- 1:[PostalCode]

Now we want to build the DAL for Person. How should the PersonBO look and when does the joins occure? Is it a business-layer problem to fetch all citynames and possible addressses pr. Person? or should the DAL complete all this before returning the PersonBO to the BAL ?

Class PersonBO 
{
    public int ID {get;set;}
    public string Name {get;set;}
    public List<AddressBO> {get;set;} // Question #1
} 

// Q1: do we retrieve the objects before returning the PersonBO and should it be an Array instead? or is this totally wrong for n-tier/3-tier??

Class AddressBO 
{
    public int ID {get;set;}
    public string StreetName {get;set;}
    public int PostalCode {get;set;} // Question #2
} 

// Q2: do we make the lookup or just leave the PostalCode for later lookup?

Can anyone explain in what order to pull which objects? Constructive criticism is very welcome. :o)

도움이 되었습니까?

해결책

You're kind of reinventing the wheel; ORMs already solve most of this problem for you and you're going to find it a little tricky to do yourself.

The way ORMs like Linq to SQL, Entity Framework and NHibernate do this is a technique called lazy loading of associations (which can optionally be overriden with an eager load).

When you pull up a Person, it does not load the Address until you specifically ask for it, at which point another round-trip to the database occurs (lazy load). You can also specify on a per-query basis that you want the Address to be loaded for every person (eager load).

In a sense, with this question you are basically asking whether or not you should perform lazy or eager loads of the AddressBO for the PersonBO, and the answer is: neither. There isn't one single approach that universally works. By default you should probably lazy load, so that you don't do a whole lot of unnecessary joins; in order to pull this off, you'll have to build your PersonBO with a lazy-loading mechanism that maintains some reference to the DAL. But you'll still want to have the option to eager-load, which you'll need to build into your "business-access" logic.

Another option, if you need to return a highly-customized data set with specific properties populated from many different tables, is to not return a PersonBO at all, but instead use a Data Transfer Object (DTO). If you implement a default lazy-loading mechanism, you can sometimes substitute this as the eager-loading version.


FYI, lazy loaders in data access frameworks are usually built with the loading logic in the association itself:

public class PersonBO
{
    public int ID { get; set; }
    public string Name { get; set; }
    public IList<AddressBO> Addresses { get; set; }
}

This is just a POCO, the magic happens in the actual list implementation:

// NOT A PRODUCTION-READY IMPLEMENTATION - DO NOT USE

internal class LazyLoadList<T> : IList<T>
{
    private IQueryable<T> query;
    private List<T> items;

    public LazyLoadList(IQueryable<T> query)
    {
        if (query == null)
            throw new ArgumentNullException("query");
        this.query = query;
    }

    private void Materialize()
    {
        if (items == null)
            items = query.ToList();
    }

    public void Add(T item)
    {
        Materialize();
        items.Add(item);
    }

    // Etc.
}

(This obviously isn't production-grade, it's just to demonstrate the technique; you start with a query and don't materialize the actual list until you have to.)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top