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

时间:2014-03-20 21:05:09

标签: c# entity-framework dbset

我正在尝试定义自己的DbSet,例如:

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

并在DbContext中使用它

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

我面临的问题是Users在运行时将为空(因此无用)但我无法理解为什么。 db.Users.Any(之类的内容会抛出"value cannot be null";如果我替换并使用DbSet而不是像

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

一切正常。

有人知道我是否以及如何解决这个问题,以便我可以使用自己的派生类?

修改

在收到一些评论之后,我澄清了为什么我这样做:我希望能够轻松地从数据检索机制切换到另一个而无需更改代码。例如,如果我决定在内存中进行缓存(缓存只是一个例子,我可能也想改变其他一些东西)我只是覆盖Any/Find/...中的MyDbSet并从字典中读取而不是查询数据库,而是保持其余代码不变。通过这种方式,代码将会定期执行#34;操作,而不关心如何检索数据。 因此,如果有人可以指出一种方法来做到这一点而不扩展也将回答问题的DbSet类。

非常感谢

1 个答案:

答案 0 :(得分:1)

我已经走过这条路几次了,并且理解让它以这种方式工作的愿望,但根据我的经验,这是不可行的,或者如果是,不值得努力。原因是许多不同的存储引擎(包括内存缓存)具有不能轻易融入EF的差异。例如,DbSet的一个简单的内存缓存实现可能不会遵循事务,懒惰或急切加载方案等。我的想法是我希望能够交换Azure表存储。但是,通过排序,分页和查询并不像SQL Server那样丰富。您可以使用SQL执行的某些查询无法使用Azure表。最后,我总是回过头来相信替换EF背后的持久性引擎的能力听起来很吸引人,但是比实现几个类更复杂 - 在我的应用程序中通常不值得。

如果我想支持缓存并且正在使用ASP.NET Web API,我会考虑使用ASP.NET缓存,以便在此时缓存API请求/响应。

如果我想要支持不同的关系数据库供应商,我会使用第三方EF提供商:A list of Entity Framework providers for various databases顺便提一下,他们确实链接到缓存和跟踪EF提供商 - 不知道这是否适用于新的EF。

如果我想在数据层内部进行缓存,或者多个存储引擎完全不同(即Mongo,Azure和SQL),我会在EF层“上方”进行缓存。像这样:

 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
     }

 }

也就是说,对于我的大多数应用程序,当我考虑它时,交换持久性引擎的能力并不是真正的要求。我的客户不“有些想要SQL,有些想要Azure表”。这可能只是由于我们所做的工作类型,但最终,它最终成为我只接受并直接编码到EF的依赖。