如何将ApplicationDbContext制作成一个接口类?

3
我正在尝试将ApplicationDbContext制作成一个接口,该接口扩展了IdentityDbContext。
 public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, 
                                     IApplicationDbContext
 {
    public ApplicationDbContext()
        : base("AppContext")
    {

    }
   // Should I add below line? without any unwanted behavior?
   // public DbSet<ApplicationUser> User { get; set;}
    public  DbSet<Book> Books { get; set; }
 }

我的界面将会是

 public interface IApplicationDbContext : IDisposable
 {
     // Should I add below line?
     // DbSet<ApplicationUser> User { get;}
     DbSet<Book> Books { get; }
     int SaveChanges();
 }

这种方法的问题在于我失去了来自IdentityDbContext.Users的'Users'访问权限

 private ApplicationDbContext ctx = new ApplicationDbContext();

 ctx.Users.somthing() works

但是使用以下代码,编译器会报错。
 private IApplicationDbContext ctx = new ApplicationDbCOntext();

 ctx.Users.something..

IApplicationDbContext没有定义'Users',也没有扩展方法'Users'...

我认为我在这里缺少一个关键概念。

你能帮助我吗?

1个回答

2
如果您将ctx声明为IApplicationDbContext的实例,那么您声明了您只希望了解IApplicationDbContext接口中的内容,而不管接口的具体实现是什么。
如果您想要访问IdentityDbContext<ApplicationUser>成员和IApplicationDbContext成员,您需要声明一个既是这两者的类型,例如您的ApplicationDbContext类。
或者更好的方法是,不要在ApplicationDbContext的具体实现中扩展IdentityDbContext<ApplicationUser>,而是遵循优先使用组合而非继承的原则,并允许ApplicationDbContext拥有IdentityDbContext<ApplicationUser>的实例,例如:
public class ApplicationDbContext : IApplicationDbContext
{
    private readonly IdentityDbContext<ApplicationUser> _dbContext;
    public IDbSet<ApplicationUser> Users { get { return _dbContext.Users; } }

    public ApplicationDbContext(IdentityDbContext<ApplicationUser> dbContext)
    {
        _dbContext = dbContext;
    }

    public DbSet<Book> Books { get; set; }
}

如果需要的话,您可以更改接口定义以提供Users属性。这样,您仍然可以访问所需的信息,同时隐藏您不需要的信息。有关更多信息,请参见http://en.wikipedia.org/wiki/Composition_over_inheritancehttp://en.wikipedia.org/wiki/Information_hiding

请检查我的更新 - 没有单一的“正确”方法,但根据你所展示的内容,我会反对扩展。 - Preston Guillot
谢谢。为什么要使用IDbSet<ApplicationUser>而不是Dbset<ApplicationUser>? - CodeSchool JJ
我在查看http://msdn.microsoft.com/en-us/library/dn497626(v=vs.108).aspx,那是那个属性的类型,但我不确定你实际上是否正在使用那个类。更一般地说,暴露接口比暴露具体实现更可取,原因与上述相同 - 依赖于抽象允许灵活更改而不影响类的客户端。一个具体的例子是,在对依赖于IApplicationDbContext的类创建单元测试时,如果其返回值也容易进行模拟,则创建虚假/模拟实现要容易得多。 - Preston Guillot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接