如何在不依赖公共数据上下文实例的情况下维护相关实体之间的引用透明度?

时间:2014-07-19 17:41:25

标签: c# .net entity-framework

感谢您的光临。

背景

在我的.NET应用程序中,我通常有一个业务逻辑层(BLL),其中包含我的业务方法和数据访问层(DAL),其中包含我的Entitiy类和处理原子实体的任何方法(即单个的CRUD方法)实体)。这是一种非常典型的设计模式。

这是我的意思的伪代码示例:

BLL

public static int CreateProduct(ProductModel product){
    return DAL.SomeClass.CreateProduct(new DAL.Product{
       Name = product.Name,
       Price = product.Price
    });
}

DAL

public int CreateProduct(Product p){
    var db = new MyDataContext();        
    db.Products.AddObject(p);
    db.SaveChanges();
    return p.Id;
}

这个简单的例子没问题。

理想情况下,实例化数据上下文和使用该数据上下文的所有业务都存在于DAL中。但如果我尝试处理稍微复杂的对象,这就成了一个问题:

BLL

public static int CreateProduct(ProductModel product){
    return DAL.SomeClass.CreateProduct(new DAL.Product{
       Name = product.Name,
       Price = product.Price,
       ProductType = DAL.SomeClass.GetProductTypeById(product.ProductTypeId) //<--PROBLEM
    });
}

现在,我没有保存实体,而是收到以下错误:

An entity object cannot be referenced by multiple instances of IEntityChangeTracker

好的,所以处理这个问题的答案是将一个公共数据上下文传递给两个调用:

BLL

    public static int CreateProduct(ProductModel product){

using{var db = new DAL.MyDataContext()){

        return DAL.SomeClass.CreateProduct(new DAL.Product{
           Name = product.Name,
           Price = product.Price,
           ProductType = DAL.SomeClass.GetProductTypeById(product.ProductTypeId, db) //<--CONTEXT
        }, db); //<--CONTEXT
    }
}

问题

这解决了眼前的问题,但现在我的参考透明度被吹了,因为我必须:

  1. 在BLL中实例化数据上下文
  2. 将数据上下文传递给BLL中的DAL
  3. 在DAL中创建接受数据上下文作为参数的重写方法。
  4. 这对某些人来说可能不是问题,但对我而言,因为我以更实用的方式编写代码,这是一个大问题。毕竟它是完全相同的数据库,那么为什么我不能处理独特的实体而不管它们的数据上下文实例呢?

    其他注释

    我意识到有些人可能会想简单地说为所有调用创建一个公共数据上下文。这样做不会因为多种原因这样做是不好的做法,并最终导致连接池溢出。 See this great answer for more details

    赞赏任何有建设性的意见。

1 个答案:

答案 0 :(得分:2)

就个人而言,我会跟踪我的工作单元并通过静态方法将数据上下文与之关联起来。如果您没有谈论具有长生命周期的操作,例如我当前的项目,ASP.NET应用程序,其中每个请求都是(大部分)不同的单元,并且请求的开始和结束与单元启动一致,那么这非常有用。 /结束。我将数据上下文存储在请求CurrentContext中,如果您不熟悉它,它基本上是由系统管理的字典,它分配静态方法可访问的特定于请求的存储。我已经为我做了一些工作,但你可以找到很多实现你自己的工作单元模式的例子。 One DbContext per web request... why?

对于许多人来说,另一个同样可行的答案是注射。用于此目的(注入datacontext),它基本上模仿了你在问题结束时编写的代码,但保护你免受&#34;无功能&#34;你不喜欢的东西。

是的,您只访问一个数据库,但如果仔细观察,您会发现数据库不是此处的约束。这是由缓存产生的,设计以允许多个不同的并发数据副本。如果您不希望允许,那么您可以获得许多其他解决方案。