简体   繁体   English

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

[英]How do I maintain referential transparency between related entities without relying on a common data context instance?

Thanks for looking. 谢谢你的期待。

Background 背景

In my .NET applications I usually have a Business Logic Layer (BLL) containing my business methods and a Data Access Layer (DAL) which contains my Entitiy classes and any methods for dealing with atomic entities (ie CRUD methods for a single entity). 在我的.NET应用程序中,我通常有一个业务逻辑层(BLL)包含我的业务方法和一个数据访问层(DAL),它包含我的Entitiy类和处理原子实体的任何方法(即单个实体的CRUD方法)。 This is a pretty typical design pattern. 这是一种非常典型的设计模式。

Here is a pseudocode example of what I mean: 这是我的意思的伪代码示例:

BLL BLL

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

DAL DAL

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

No problems with this simple example. 这个简单的例子没问题。

Ideally, all the business of instantiating a data context and using that data context lives in the DAL. 理想情况下,实例化数据上下文和使用该数据上下文的所有业务都存在于DAL中。 But this becomes a problem if I attempt to deal with slightly more complex objects: 但是,如果我尝试处理稍微复杂的对象,这就成了一个问题:

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

Now, instead of saving the entity, I get the following error: 现在,我没有保存实体,而是收到以下错误:

An entity object cannot be referenced by multiple instances of IEntityChangeTracker

Ok, so the answer to dealing with that is to pass a common data context to both calls: 好的,所以处理这个问题的答案是将一个公共数据上下文传递给两个调用:

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

Problem 问题

This solves the immediate problem, but now my referential transparency is blown because I have to: 这解决了眼前的问题,但现在我的参考透明度被吹了,因为我必须:

  1. Instantiate the data context in the BLL 在BLL中实例化数据上下文
  2. Pass the data context to the DAL from the BLL 将数据上下文从BLL传递给DAL
  3. Create overridden methods in the DAL that accept a data context as a parameter. 在DAL中创建接受数据上下文作为参数的重写方法。

This may not be a problem for some but for me, since I write my code in a more functional style, it is a big problem. 这对某些人来说可能不是问题,但对我而言,因为我以更实用的方式编写代码,这是一个大问题。 It's all the same database after all, so why the heck can't I deal with unique entities regardless of their data context instance? 毕竟它是完全相同的数据库,那么为什么我不能处理独特的实体而不管它们的数据上下文实例呢?

Other Notes 其他说明

I realize that some may be tempted to simply say to create a common data context for all calls. 我意识到有些人可能只想说为所有调用创建一个公共数据上下文。 This won't fly as doing so is bad practice for a multitude of reasons and ultimately causes a connection pool overflow. 这样做不会因为多种原因这样做是不好的做法,并最终导致连接池溢出。 See this great answer for more details . 有关详细信息,请参阅此优秀答案

Any constructive input is appreciated. 任何建设性的意见表示赞赏。

Personally, I track my unit of work and associate a data context to it via static methods. 就个人而言,我通过静态方法跟踪我的工作单元并将数据上下文与之关联起来。 This works great if you aren't talking about operations with long lifetimes, such as my current project, an ASP.NET application, where every request is a (mostly) distinct unit and a request start and end coincide with the unit start/end. 如果您不是在谈论具有长生命周期的操作,例如我当前的项目,ASP.NET应用程序,其中每个请求都是(大部分)不同的单元,并且请求的开始和结束与单元的开始/结束一致,那么这很有用。 。 I store data context in the request CurrentContext, which, if you aren't familiar with it, is basically a dictionary managed by the system that allocates a request-specific storage accessible by static methods. 我将数据上下文存储在请求CurrentContext中,如果您不熟悉它,它基本上是由系统管理的字典,它分配静态方法可访问的特定于请求的存储。 The work's already done for me there, but you can find lots of examples of implementing your own unit of work pattern. 这项工作已经为我做了,但你可以找到很多实现你自己的工作单元模式的例子。 One DbContext per web request... why? 每个网络请求一个DbContext ...为什么?

Another equally workable answer for many is injection. 另一个同样可行的答案是注射。 Used for this purpose (injecting datacontext), it basically mimics the code you wrote at the end of your question, but shields you from the "non-functional" stuff you dislike. 用于此目的(注入datacontext),它基本上模仿了你在问题结束时编写的代码,但屏蔽了你不喜欢的“非功能性”东西。

Yes, you are only accessing one database, but if you look closely, you will see the database is not the constraint here. 是的,您只访问一个数据库,但如果仔细观察,您会看到数据库不是此处的约束。 That is arising from the cache, which is designed to permit multiple, differing, concurrent copies of the data. 这是由缓存引起的,缓存旨在允许多个不同的并发数据副本。 If you don't wish to permit that, then you have a whole host of other solutions available. 如果您不希望允许,那么您可以获得许多其他解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM