实体框架:如何扩展DbSet

本文关键字:DbSet type 扩展 框架 何扩展 实体 | 更新日期: 2023-09-27 17:51:07

我正在尝试定义我自己的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; }

一切正常

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

编辑:

在收到一些评论后,我澄清了我这样做的原因:我希望能够轻松地从数据检索机制切换到另一种机制,而无需更改代码。例如,如果我决定在内存中做缓存(缓存只是一个例子,它可能是我想改变一些其他的东西,以及),我只是覆盖MyDbSet中的Any/Find/...,从字典中读取,而不是查询数据库,留下代码的其余部分不变。通过这种方式,代码将执行"常规"操作,而无需考虑如何在后面检索数据。因此,如果有人可以指出一个方法来做到这一点,而不扩展DbSet类,也将回答这个问题。

多谢

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

我已经在这条路上走了几次,并且理解让它以这种方式工作的愿望,但根据我的经验,这是不可行的,或者如果它是,不值得付出努力。原因是许多不同的存储引擎(包括内存缓存)存在差异,这些差异不容易适应EF。例如,一个微不足道的DbSet的内存缓存实现可能不支持事务、延迟或急切加载模式等。我的想法是,我希望能够在Azure表存储交换。但是排序、分页和查询并不像SQL Server那样丰富。有些查询可以用SQL执行,但不能用Azure表执行。最后,我总是回到相信替换EF背后的持久引擎的能力听起来很吸引人,但比仅仅实现几个类要复杂得多——在我的应用程序中通常不值得这样做。

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

如果我想支持不同的关系数据库供应商,我会使用第三方EF供应商:各种数据库的实体框架供应商列表。顺便说一句,他们确实链接到缓存和跟踪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。