简体   繁体   English

实体框架:如何扩展DbSet <type> ?

[英]Entity framework: how to extend DbSet<type>?

I am trying to define my own DbSet, like: 我正在尝试定义自己的DbSet,如:

public class MyDbSet<TEntity> : DbSet<TEntity>
    where TEntity : class
{
    public override TEntity Add(TEntity entity)
    {
      ....

And use it in DbContext 并在DbContext中使用它

    public MyDbSet<User> Users { get; set; }

The problem I am facing is that Users will be null at runtime (and therefore useless) but I cannot figure why. 我面临的问题是Users在运行时将为空(因此无用)但我无法理解为什么。 Something like db.Users.Any( will throw a "value cannot be null" ; if I replace and use DbSet instead like db.Users.Any(类的db.Users.Any(将抛出"value cannot be null" ;如果我替换并使用DbSet而不是

    public DbSet<User> Users { get; set; }

everything works fine. 一切正常。

Does anybody know if and how can I fix this issue so I can use my own derived class? 有谁知道我是否以及如何解决这个问题所以我可以使用自己的派生类?

Edit: 编辑:

After receiving some comments, I clarify why I do this: I want to be able to switch easily from data retrieving mechanism to another without changing the code. 在收到一些评论之后,我澄清了为什么我这样做:我希望能够轻松地从数据检索机制切换到另一个而无需更改代码。 For example if I decide to do caching in memory (caching is just an example, it may be I want to change some other things as well) I just override the Any/Find/... in MyDbSet and read from a dictionary instead of querying the database, leaving the rest of the code unchanged. 例如,如果我决定在内存中进行缓存(缓存只是一个例子,我可能也想改变其他一些东西)我只是覆盖MyDbSetAny/Find/...并从字典中读取而不是查询数据库,保持其余代码不变。 This way the code will do "regular" operations without minding how the data is retrieved behind. 这样,代码将执行“常规”操作,而无需考虑如何检索数据。 So if somebody can point a method to do this without extending the DbSet class that will also answer the question. 因此,如果有人可以指出一个方法来执行此操作而不扩展也将回答问题的DbSet类。

many thanks 非常感谢

I've been down this road a couple times, and understand the desire to have it work this way, but in my experience it's not doable, or if it is, not worth the effort. 我已经走过这条路几次了,并且理解让它以这种方式工作的愿望,但根据我的经验,这是不可行的,或者如果它是,不值得努力。 The reason is that the many different storage engines (including in-memory cache) have differences that cannot be fit easily into EF. 原因是许多不同的存储引擎(包括内存缓存)具有不能轻易融入EF的差异。 For example, a trivial in-memory cached implementation of a DbSet may not honor transactions, lazy- or eager- loading schemes, etc. My thought was that I'd like to be able to swap in Azure Table Storage. 例如,DbSet的一个简单的内存缓存实现可能不会遵循事务,懒惰或急切加载方案等。我的想法是我希望能够交换Azure表存储。 But with that sorting, paging, and querying is not as rich as SQL Server. 但是,通过排序,分页和查询并不像SQL Server那样丰富。 Some queries you can do with SQL you just can't do with Azure Tables. 您可以使用SQL执行的某些查询无法使用Azure表。 In the end, I always come back to believing that the ability to swap out persistence engines behind EF sounds appealing, but is way more complex than just implementing a few classes- and in my apps not usually worth it. 最后,我总是回过头来相信,替换EF背后的持久性引擎的能力听起来很吸引人,但是比实现几个类更复杂 - 在我的应用程序中通常不值得。

If I wanted to support caching and was doing an ASP.NET Web API, I would consider using ASP.NET caching so that API requests/responses were cached at that point. 如果我想支持缓存并且正在使用ASP.NET Web API,我会考虑使用ASP.NET缓存,以便在那时缓存API请求/响应。

If I wanted support for different relational DB vendors, I would use the 3rd party EF Providers: A list of Entity Framework providers for various databases Incidentally, they do link to Caching and Tracing EF Providers- no idea if that works for newer EF. 如果我想要支持不同的关系数据库供应商,我会使用第三方EF提供商: 各种数据库的实体框架提供商列表顺便提一下,他们确实链接到缓存和跟踪EF提供商 - 不知道这是否适用于新的EF。

If I wanted caching inside the data layer, or multiple storage engines that were drastically different (ie Mongo, Azure, and SQL), I would do it "above" the EF layer. 如果我想在数据层内部进行缓存,或者需要多个存储引擎(即Mongo,Azure和SQL),我会在EF层“上方”进行缓存。 Something like this: 像这样的东西:

 public interface ISomeDataProvider
 {
     SomeType Find(int id); 
     ....
 }

 public class EfDataProvider : ISomeDataProvider
 {
     private SomeAppDbContext db = new SomeAppDbContext();
     public SomeType Find(int id){
         return db.SomeTypes.Find(id);
     }

 }

 public class AzureTableDataProvider : ISomeDataProvider
 {
     public SomeType Find(int id){
         return //Azure Table code
     }

 }

 public class CachingDataProvider : ISomeDataProvider
 {
     private ISomeDataProvider source;
     private static IList<SomeType> cache = new List<SomeType>(); //List used here, but could use .NET Cache, Redis, etc.
     public CachingDataProvider(ISomeDataProvider source){
            this.source = source;
     }
     public SomeType Find(int id){
         var result = cache.SingleOrDefault(x=>x.Id == id)
         if(result == null){
             result = source.SingleOrDefault(x=>x.Id == id)
             if(result != null) cache.Add(result); //Again, trivial cache example.  Cache expiration, refresh, loading, etc. should be considered per-app
         }
         return result
     }

 }

That said, for the majority of my applications, when I think about it, the ability to swap out persistence engines isn't really a requirement. 也就是说,对于我的大多数应用程序,当我考虑它时,交换持久性引擎的能力并不是真正的要求。 My customers don't "some want SQL, some want Azure Tables". 我的客户不“有些想要SQL,有些想要Azure表”。 That may just be due to the type of work we do, but in the end, it ends up being a dependency I just accept and code directly to EF. 这可能只是由于我们所做的工作类型,但最终,它最终成为我只接受并直接编码到EF的依赖。

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

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