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

谢谢你的期待.

背景

在我的.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
    });
}

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

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

问题

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

>在BLL中实例化数据上下文
>将数据上下文从BLL传递给DAL
>在DAL中创建接受数据上下文作为参数的重写方法.

这对某些人来说可能不是问题,但对我而言,因为我以更实用的方式编写代码,这是一个大问题.毕竟它是完全相同的数据库,那么为什么我不能处理独特的实体而不管它们的数据上下文实例呢?

其他说明

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

任何建设性的意见表示赞赏.

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

另一个同样可行的答案是注射.用于此目的(注入datacontext),它基本上模仿了你在问题结束时编写的代码,但屏蔽了你不喜欢的“非功能性”东西.

是的,您只访问一个数据库,但如果仔细观察,您会看到数据库不是此处的约束.这是由缓存引起的,缓存旨在允许多个不同的并发数据副本.如果您不希望允许,那么您可以获得许多其他解决方案.

点赞