views:

140

answers:

2

Hi guys

In the context of the n-tier application, is there a difference between what you would consider your data access classes to be and your repositories?

I tend to think yes but I just wanted to see what other thought. My thinking is that the job of the repository is just to contain and execute the raw query itself, where as the data access class would create the context, execute the repository (passing in the context), handle mapping the data model to the domain model and return the result back up...

What do you guys think? Also do you see any of this changing in a Linq to XML scenario (assuming that you change the context for the relevant XDocument)?

Cheers Anthony

UPDATE:

This is the way that I would have typically implemented things previously:

public class TermBl : ITermBl
{
    public IEnumerable<ITerm> GetAll(IListParameter criteria)
    {
        //Any pre business logic

        var dataLayer = this.CreateDataLayer();
        var result = dataLayer.GetAll(criteria);

        //Any post business logic

        return result;
    }

    ... Other methods
}

public class TermDa : ITermDa
{
    public IEnumerable<ITerm> GetAll(IListParameter criteria)
    {
        //Linq query
        var dataResult = ....ToList()

        var mappedResult = this.FromDataToDomain(dataResult);   
        //Note the mapping isn't done in this object, the actual 
        //  mapping is handled by a separate component

        return mappedResult;
    }

    ... Other methods
}

Do you see any inherent problems here with the pattern in general...

As for the repository where I have been thinking of using the it is instead of having the query directly in the TermDa's GetAll method I would change it to look something more like this:

public class TermDa : ITermDa
{
    public IEnumerable<ITerm> GetAll(IListParameter criteria)
    {
        var repository = this.CreateRepository();
        var dataResult = repository.GetAll(..., criteria).ToList();

        var mappedResult = this.FromDataToDomain(dataResult);

        return mappedResult;
    }

    ... Other methods
}

public class TermRepository : ITermRepository 
{
    public IQueryable<ITerm> GetAll(IMyContext context, IListParameter criteria)
    {
        //Linq query
        return  ...;
    }

    ... Other queries
}

Is this how you guys see it working or not really... With or without the repository I see either of the above totally protecting the business layer from knowing anything about the data access methods/technology used...

+3  A: 

Yes, there is a major difference.

  • A DAL (such as a Table Data Gateway) is a database concept. It is responsible for issuing queries to the database and returning record sets.

  • A repository is a domain concept. It is responsible for accepting structured requests and returning strongly-typed objects.

Very different in practice.


Update:

The question seems to reflect a significant amount of confusion, so let me try to clarify with a code example. Here's a design you might use if you weren't using any ORM and were doing all of your own mapping instead. None of this is production-quality code, it's just for educational purposes:

Data Access:

public interface IOrderData
{
    IDataReader GetOrder(int orderID);
}

public interface IOrderDetailData
{
    IDataReader GetOrderDetails(int orderID);
}

public interface IProductData
{
    IDataReader GetProduct(int productID);
}

Domain:

public class Order
{
    public int ID { get; set; }
    public DateTime Date { get; set; }
    public OrderStatus Status { get; set; }
    // etc.
    public IList<OrderDetail> Details { get; set; }
}

public class OrderDetail
{
    public int ID { get; set; }
    public Product Product { get; set; }
    public int Quantity { get; set; }
}

Mapping:

public interface IDataMapper
{
    Order MapOrder(IDataRecord record);
    OrderDetail MapOrderDetail(IDataRecord record);
    Product MapProduct(IDataRecord record);
}

Repository:

public interface IOrderRepository
{
    Order GetOrder(int orderID);
}

public class OrderRepository
{
    // These get initialized in the constructor
    private readonly IOrderData orderData;
    private readonly IOrderDetailData orderDetailData;
    private readonly IProductData productData;
    private readonly IDataMapper mapper;

    public Order GetOrder(int orderID)
    {
        Order order;
        using (IDataReader orderReader = orderData.GetOrder(orderID))
        {
            if (!orderReader.Read())
                return null;
            order = mapper.MapOrder(orderReader);
        }
        using (IDataReader detailReader = 
            orderDetailData.GetOrderDetails(orderID))
        {
            while (detailReader.Read())
            {
                OrderDetail detail = mapper.MapOrderDetail(detailReader);
                detail.Product = ...;  // Omitted for brevity, more reading/mapping
                order.Details.Add(detail);
            }
        }
        return order;
    }
}

Is this making more sense now? The DAL is dealing with data. The concrete Repository may encapsulate data access classes but the abstract repository (its public interface) only deals with domain classes.

Once again I'll just remind readers that this is not even close to production-quality code, and that most apps today use an ORM or at least some better form of automatic mapping. This is for illustrative purposes only.

Aaronaught
So do you see a DAL object using a repository object? i.e. when you say issuing queries, I think that it would do this by calling the repository... almost like the repository is a proxy to stored procs in a database, except the queries are in the repository...
vdh_ant
@vdh_ant: No, a DAL generally doesn't have any knowledge of the domain model. A repository's implementation (not its interface/base type) might use the DAL, although most new projects today don't even have a DAL, it's all encapsulated in an ORM. The repository is **not** a proxy to database objects, you've misunderstood what it is.
Aaronaught
@Aaronaught: putting the repository a side for a sec, when you say "DAL generally doesn't have any knowledge of the domain model" this goes against what I have seen around the place... thinking from an interface/contract perspective the DAL has to return something and I have mainly seen that something to be the domain model. When I think about what else it could be it could only be the data models... I would have thought this was bad for several reasons. Mainly because your business logic layer is now coupled to a data model which is specific to different technologies...
vdh_ant
For instance if my DAL was using EF I wouldn't want to return the entity framework models from the DAL because when I want to switch to something else (not that I have seen it typically done but I find it useful to think of the level of coupling this way) I would probably be ditching EF data models and replacing them with something else. Again if my DAL is return data models, this puts me in a really bad place when face with the described scenario... So to me the only thing you are left with is that the DAL needs to know how to map from a give data model to the relevant domain models...
vdh_ant
@vdh_ant: You're overcomplicating this. DAL = Data Access Layer. It deals with Data Objects, mainly record sets. You might have a mapper that converts record sets to domain model classes (this is what an ORM does), but that is not part of the DAL, it's really a separate component altogether. Fowler calls it the "Assembler." Repository classes tend to encapsulate all of the functionality of the DAL, plus any mapping that needs to be done before/after.
Aaronaught
@Aaronaught: Ok I think get what you are getting at, but in practice where does that fit into the code samples I provided (with and without a repository)??
vdh_ant
@vdh_ant: It doesn't. What you're calling a "data" layer has far too many responsibilities. It's acting as the data layer, the mapping layer AND part of the domain model. Although on the last example you appear to be using Linq to SQL or EF or some other ORM, in which case the data layer is part of the ORM itself, so I'm not really sure what to call that... it seems to just be a redundant proxy. It doesn't make sense, because you seem to be mapping from one type to *the same type*. It's all mixed up.
Aaronaught
+1  A: 

You seem to have a good handle on it. "Data Access classes" can take a lot of different shapes. It's some sort of class that has something to do with data access. Your Repository is (A) a pattern for handling your data persistence, and (B) a place within your data access scheme (if you're implementing repository).

A challenge in your data access strategy is providing flexibility and reusable capability at the same time. While at the same time being efficient. While at the same time working with your business logic, being decoupled but also being cohesive. Tricky.

Repository is a pattern that purports to help with all this balance. Your code for translating the db (or whatever) to/from entity classes resides in one place, for each entity. Your "Data Access classes" might consist of your repository classes, as well as classes that actually handle sql work. You certainly should not be doing all the sql cruft within each of your repository classes.

Example: you could start off using inefficient-but-easy reflection to fill out your entity objects, doing close to no work in your repository classes; later you can make it more efficient for high-volume entities, but this is completely hidden from other parts of your system. And then later you move some configuration to XML, but the rest of your system has no idea of this change.

LINQ-to-sql and Entity framework really leverage the repository pattern, because what the repository classes return is actually an IQuerable of that entity. Business classes can apply additional criteria, and those criteria actually make it to the sql, while still providing complete encapsulation from the data persistence. It's seriously cool.

Patrick Karcher
@Patrick Karcher: So do you see a DAL object using a repository or do you see the repositories as a different type of DAL or that there is no overlap... i.e. you chose to use a DAL or a repository from your business layer...
vdh_ant
@vdh_ant If you have a repository, you could say it's half in your DAL and half above it. Better to say it *links* your DAL with everything above that. Or, you could see it as your repository *uses* the DAL (completely hidden from all your UI and business layer) to persist your data. **Or**, you might have your sqlconnections and such **in** your repository classes. If this is the case, you could point at your repository classes and call them the DAL; probably a "DAL+", since it not only get/puts your data but wraps it particularly nicely for the rest of your app. **DAL is a vague term!**
Patrick Karcher
@vdh_ant What you're trying to get a handle on is (I think) the most tricky part of making a good, *flexible* app. If you're confused about what exactly people mean by DAL, and how to best set up the "back end" of your app, you're in good company! Very smart people, paid a lot of money, are at this moment thinking, "now, how the hell do I set up my data access for *this* project . . ." By realizing you don't know the Best Way, and asking what you're asking, you're ahead of a lot of people who *believe* they have this stuff all figured out.
Patrick Karcher
Ok cool... so if I have this right... The "public" part of my Data Access --Layer-- is the repository and internally it uses data access objects which abstracts away the actual "query". Internally the repository still has knowledge of what specifically data access technology the data access object uses, because the repository in scenarios like EF/L2S the repository will creates the context and passes it into the data access object. Also the data access object, returns the data access representation of a given entity and the repository returns the typed business entities... Is that about right?
vdh_ant
Yes, you got it. The repository knows completely how the data is persisted, and keeps that from the outside world. It gets interesting with EF/L2S because you might have the repository return the defined IQuerable objects, which in turn might get wrapped/used by business objects, or might get beefed up themselves with business functionality; You would then use Linq(toSql) in your business/UI/controller logic. In this scenerio the Repository is pretty "light", not actually doing much for you on the read side. There's just so many ways to do it. But you have a good handle on it.
Patrick Karcher