存储库与数据访问

时间:2010-05-06 13:29:45

标签: linq linq-to-sql linq-to-xml repository-pattern

在n层应用程序的上下文中,您认为数据访问类与存储库之间存在差异吗?

我倾向于认为是,但我只是想看看其他人的想法。我的想法是存储库的工作只是包含和执行原始查询本身,其中数据访问类将创建上下文,执行存储库(传递上下文),处理将数据模型映射到域模型并将结果返回...

你们觉得怎么样?您是否也看到Linq to XML场景中的任何变化(假设您更改了相关XDocument的上下文)?

干杯安东尼

更新:

这是我以前通常会实现的方式:

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
}

一般来说,你看到这种模式存在哪些固有问题......

至于我一直在考虑使用它的存储库,而不是直接在TermDa的GetAll方法中查询,我会将其更改为更像这样:

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
}

这是你们看到它是否正常工作......无论有没有存储库,我都看到上述任何一项完全保护业务层不了解所使用的数据访问方法/技术......

2 个答案:

答案 0 :(得分:9)

是的,存在重大差异。

  • DAL (例如表数据网关)是数据库概念。它负责向数据库发出查询并返回记录集。

  • 存储库概念。它负责接受结构化请求并返回强类型对象

在实践中非常不同。


<强>更新

这个问题似乎反映了很多混乱,所以让我试着用代码示例来澄清。如果您没有使用任何ORM并且正在执行所有自己的映射,那么这是您可能会使用的设计。这些都不是生产质量的代码,仅用于教育目的:

数据访问:

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

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

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

<强>域

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; }
}

<强>映射:

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

<强>存储库:

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;
    }
}

这现在更有意义吗? DAL正在处理数据。具体的存储库可以封装数据访问类,但抽象存储库(它的公共接口)只处理域类。

我再次提醒读者,这甚至不接近生产质量的代码,而今天的大多数应用程序都使用ORM或至少一些更好的自动映射形式。这仅用于说明目的。

答案 1 :(得分:1)

你似乎对它有很好的把握。 “数据访问类”可以采用许多不同的形状。这是某种与数据访问有关的类。您的存储库是(A)用于处理数据持久性的模式,以及(B)数据访问方案中的位置(如果您正在实现存储库)。

您的数据访问策略面临的挑战是同时提供灵活性和可重用功能。同时又高效。同时处理您的业务逻辑,同时解耦,但也是 cohesive 。棘手。

存储库是一种旨在帮助实现所有这些平衡的模式。用于将db(或其他)转换为实体类或从实体类转换的代码驻留在每个实体的一个位置。您的“数据访问类”可能包含您的存储库类,以及实际处理SQL工作的类。您当然不应该在每个存储库类中执行所有sql cruft。

示例:您可以开始使用低效但容易的反射来填充您的实体对象,在您的存储库类中接近不工作;稍后您可以使其对高容量实体更有效,但这完全隐藏在系统的其他部分。然后您将一些配置移动到XML,但系统的其余部分不知道这种更改。

LINQ-to-sql和Entity框架确实利用了存储库模式,因为存储库类返回的实际上是该实体的IQuerable。业务类可以应用其他条件,这些条件实际上可以使用sql,同时仍然提供数据持久性的完整封装。这真的很酷。