c# - 如何在不依赖公共(public)数据上下文实例的情况下保持相关实体之间的引用透明性?

标签 c# .net entity-framework

感谢您的关注。

背景

在我的 .NET 应用程序中,我通常有一个包含我的业务方法的业务逻辑层 (BLL) 和一个数据访问层 (DAL),其中包含我的实体类和任何处理原子实体的方法(即单个 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 的多个实例引用

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

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 中创建接受数据上下文作为参数的覆盖方法。

这对某些人来说可能不是问题,但对我来说,因为我以更函数式的风格编写代码,所以这是个大问题。毕竟都是同一个数据库,所以我到底为什么不能处理唯一实体而不考虑它们的数据上下文实例?

其他注意事项

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

欢迎任何建设性的意见。

最佳答案

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

对于许多人来说,另一个同样可行的答案是注入(inject)。用于此目的(注入(inject)数据上下文),它基本上模仿您在问题末尾编写的代码,但使您免受您不喜欢的“非功能性”内容的影响。

是的,你只是访问一个数据库,但如果你仔细观察,你会发现数据库并不是这里的约束。这是由缓存引起的,缓存被设计以允许数据的多个不同的并发副本。如果您不想允许这样做,那么您可以使用许多其他解决方案。

关于c# - 如何在不依赖公共(public)数据上下文实例的情况下保持相关实体之间的引用透明性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24843189/

相关文章:

mysql - 将 INNER JOIN 与插入和更新一起使用时,VB.Net 中出现错误

.net - 代码组织: How does Google organize it's code?

entity-framework - 如何使用 Mono 设置 Entity Framework /SQL Server

c# - 没有模型属性的 Entity Framework 映射结构/复杂类型

c# - 如何将List<T>插入数据库

c# - 在 Windows 窗体中向 SplitContainer 添加面板

c# - 如何在 C# 中监视剪贴板更改?

c# - 在 C# 中捕获键盘笔画

.net 反射程序集加载异常

c# - C#/ Entity Framework 中的 LINQ 表达式