为什么DbContext没有实现IDbContext接口?

时间:2022-09-02 12:02:24

Why there is no IDbContext interface in the Entity Framework? Wouldn't it be easier to test things if there was an existing interface with methods like SaveChanges() etc. from which you could derive your custom database context interface?

为什么Entity Framework中没有IDbContext接口?如果现有的接口有类似SaveChanges()等的方法可以从中导出自定义数据库上下文接口,那么测试是不是更容易?

public interface ICustomDbContext : IDbContext
{
    // add entity set properties to existing set of methods in IDbContext
    IDbSet<SomeEntity> SomeEntities { get; }
}

4 个解决方案

#1


13  

I see this IDbContext:

我看到这个IDbContext:

See this link And then you make a new partial class for your Entities Context With That interface.

查看此链接然后为您的实体上下文使用该界面创建一个新的分部类。

public partial class YourModelEntities : DbContext, IDbContext 

EDITED: I edited this post, This Works for me. My Context

编辑:我编辑了这篇文章,这对我有用。我的背景

namespace dao
{
    public interface ContextI : IDisposable
    {
        DbSet<TEntity> Set<TEntity>() where TEntity : class;
        DbSet Set(Type entityType);
        int SaveChanges();
        IEnumerable<DbEntityValidationResult> GetValidationErrors();
        DbEntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity:class;
        DbEntityEntry Entry(object entity);
        string ConnectionString { get; set; }
        bool AutoDetectChangedEnabled { get; set; }
        void ExecuteSqlCommand(string p, params object[] o);
        void ExecuteSqlCommand(string p);
    }
}

YourModelEntities is your auto-generated partial class, and your need to create a new partial class with the same name, then add your new context interface, for this example is ContextI

YourModelEntities是您自动生成的分部类,您需要创建一个具有相同名称的新分部类,然后添加新的上下文接口,对于此示例是ContextI

NOTE: The interface hasn't implement all methods, because the methods are implemented in your auto-generate code.

注意:接口尚未实现所有方法,因为这些方法是在自动生成代码中实现的。

namespace dao
{
    public partial class YourModelEntities :DbContext, ContextI
    {
        public string ConnectionString
        {
            get
            {
                return this.Database.Connection.ConnectionString;
            }
            set
            {
                this.Database.Connection.ConnectionString = value;
            }
        }

        bool AutoDetectChangedEnabled
        {
            get
            {
                return true;
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public void ExecuteSqlCommand(string p,params object[] os)
        {
            this.Database.ExecuteSqlCommand(p, os);
        }

        public void ExecuteSqlCommand(string p)
        {
            this.Database.ExecuteSqlCommand(p);
        }

        bool ContextI.AutoDetectChangedEnabled
        {
            get
            {
                return this.Configuration.AutoDetectChangesEnabled;
            }
            set
            {
                this.Configuration.AutoDetectChangesEnabled = value;
            }
        }

    }
}

#2


0  

I was thinking also about that, I assume you are going to use it for mocking DbContext. I find no reason for that, except that you will need to implement your own DbSet manually in your anyway for your mocked class (so will need to rewrite your own interface anyway).

我也想到了这一点,我假设你将使用它来模拟DbContext。我没有理由这样做,除了你需要手动为你的模拟类手动实现自己的DbSet(所以无论如何都需要重写你自己的界面)。

#3


0  

Just create a mock DbContext extending your production DbContext overriding the methods that complicate testing. That way, any changes to the production DbContext are automatically reflected in the tests, save for the overridden methods. For any other classes that deal with persistence and take the DbContext just extend them as well passing in the extended mock DbContext.

只需创建一个模拟DbContext,扩展您的生产DbContext,覆盖使测试复杂化的方法。这样,生产DbContext的任何更改都会自动反映在测试中,除了重写的方法。对于处理持久性的任何其他类,并采用DbContext只是扩展它们以及传递扩展模拟DbContext。

namespace Test.Mocks
{  
    public sealed class MockDatabaseContext : MainProject.Persistence.Database.DatabaseContext
    {
        public MockDatabaseContext(ConfigurationWrapper config) : base(config)
        {

        }      
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {

            var dbPath = "test.db";
            optionsBuilder.UseSqlite($"Filename={dbPath}");


        }
    }
}

namespace Test.Mocks
{

    public class MockInventoryFacade : InventoryFacade
    {        
        public MockInventoryFacade(MockDatabaseContext databaseContext) : base(databaseContext)
        {

        }    
    }
}

#4


-12  

There is no IDbContext because it would be useless, the only implementation of it would be the DbContext.

没有IDbContext因为它没用,它的唯一实现就是DbContext。

EF team is also going this way with IDbSet if you look at this design meeting note

如果您查看此设计会议记录,EF团队也会使用IDbSet

For me, the real problem with EF when it comes to unit testing is the DbConnection in the DbContext, fortunately there is Effort a nice project on codeplex that starts to fill this.

对我来说,EF在单元测试方面的真正问题是DbContext中的DbConnection,幸运的是,在Codeplex上有一个很好的项目开始填充它。

Effort is a powerful tool that enables a convenient way to create automated tests for Entity Framework based applications. It is basically an ADO.NET provider that executes all the data operations on a lightweight in-process main memory database instead of a traditional external database. It provides some intuitive helper methods too that make really easy to use this provider with existing ObjectContext or DbContext classes. A simple addition to existing code might be enough to create data driven tests that can run without the presence of the external database.

Effort是一个功能强大的工具,可以方便地为基于Entity Framework的应用程序创建自动化测试。它基本上是一个ADO.NET提供程序,它在轻量级进程内主数据库而不是传统的外部数据库上执行所有数据操作。它提供了一些直观的帮助方法,使得这个提供程序与现有的ObjectContext或DbContext类一起使用非常容易。对现有代码的简单添加可能足以创建可在没有外部数据库的情况下运行的数据驱动测试。

With this, you can leave your DbContext and DbSet as is and do your unit tests easily. The only drawback with this is the difference between Linq providers where some unit tests may pass with effort and not with the real backend.

有了这个,您可以保留DbContext和DbSet,并轻松进行单元测试。唯一的缺点是Linq提供商之间的差异,其中一些单元测试可能会通过努力而不是真正的后端。

UPDATE with EF7

使用EF7更新

I still maintain that IDbContext would be useless and the problem comes from the DbConnection.

我仍然认为IDbContext没用,问题来自DbConnection。

EF7 will not have an IDbContext either, in order to do unit testing they are now giving an in memory provider.

EF7也没有IDbContext,为了进行单元测试,他们现在提供内存提供程序。

You can see Rowan Miller doing a demo here: Modern Data Applications with Entity Framework 7

你可以看到Rowan Miller在这里做一个演示:带有Entity Framework 7的现代数据应用程序

#1


13  

I see this IDbContext:

我看到这个IDbContext:

See this link And then you make a new partial class for your Entities Context With That interface.

查看此链接然后为您的实体上下文使用该界面创建一个新的分部类。

public partial class YourModelEntities : DbContext, IDbContext 

EDITED: I edited this post, This Works for me. My Context

编辑:我编辑了这篇文章,这对我有用。我的背景

namespace dao
{
    public interface ContextI : IDisposable
    {
        DbSet<TEntity> Set<TEntity>() where TEntity : class;
        DbSet Set(Type entityType);
        int SaveChanges();
        IEnumerable<DbEntityValidationResult> GetValidationErrors();
        DbEntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity:class;
        DbEntityEntry Entry(object entity);
        string ConnectionString { get; set; }
        bool AutoDetectChangedEnabled { get; set; }
        void ExecuteSqlCommand(string p, params object[] o);
        void ExecuteSqlCommand(string p);
    }
}

YourModelEntities is your auto-generated partial class, and your need to create a new partial class with the same name, then add your new context interface, for this example is ContextI

YourModelEntities是您自动生成的分部类,您需要创建一个具有相同名称的新分部类,然后添加新的上下文接口,对于此示例是ContextI

NOTE: The interface hasn't implement all methods, because the methods are implemented in your auto-generate code.

注意:接口尚未实现所有方法,因为这些方法是在自动生成代码中实现的。

namespace dao
{
    public partial class YourModelEntities :DbContext, ContextI
    {
        public string ConnectionString
        {
            get
            {
                return this.Database.Connection.ConnectionString;
            }
            set
            {
                this.Database.Connection.ConnectionString = value;
            }
        }

        bool AutoDetectChangedEnabled
        {
            get
            {
                return true;
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public void ExecuteSqlCommand(string p,params object[] os)
        {
            this.Database.ExecuteSqlCommand(p, os);
        }

        public void ExecuteSqlCommand(string p)
        {
            this.Database.ExecuteSqlCommand(p);
        }

        bool ContextI.AutoDetectChangedEnabled
        {
            get
            {
                return this.Configuration.AutoDetectChangesEnabled;
            }
            set
            {
                this.Configuration.AutoDetectChangesEnabled = value;
            }
        }

    }
}

#2


0  

I was thinking also about that, I assume you are going to use it for mocking DbContext. I find no reason for that, except that you will need to implement your own DbSet manually in your anyway for your mocked class (so will need to rewrite your own interface anyway).

我也想到了这一点,我假设你将使用它来模拟DbContext。我没有理由这样做,除了你需要手动为你的模拟类手动实现自己的DbSet(所以无论如何都需要重写你自己的界面)。

#3


0  

Just create a mock DbContext extending your production DbContext overriding the methods that complicate testing. That way, any changes to the production DbContext are automatically reflected in the tests, save for the overridden methods. For any other classes that deal with persistence and take the DbContext just extend them as well passing in the extended mock DbContext.

只需创建一个模拟DbContext,扩展您的生产DbContext,覆盖使测试复杂化的方法。这样,生产DbContext的任何更改都会自动反映在测试中,除了重写的方法。对于处理持久性的任何其他类,并采用DbContext只是扩展它们以及传递扩展模拟DbContext。

namespace Test.Mocks
{  
    public sealed class MockDatabaseContext : MainProject.Persistence.Database.DatabaseContext
    {
        public MockDatabaseContext(ConfigurationWrapper config) : base(config)
        {

        }      
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {

            var dbPath = "test.db";
            optionsBuilder.UseSqlite($"Filename={dbPath}");


        }
    }
}

namespace Test.Mocks
{

    public class MockInventoryFacade : InventoryFacade
    {        
        public MockInventoryFacade(MockDatabaseContext databaseContext) : base(databaseContext)
        {

        }    
    }
}

#4


-12  

There is no IDbContext because it would be useless, the only implementation of it would be the DbContext.

没有IDbContext因为它没用,它的唯一实现就是DbContext。

EF team is also going this way with IDbSet if you look at this design meeting note

如果您查看此设计会议记录,EF团队也会使用IDbSet

For me, the real problem with EF when it comes to unit testing is the DbConnection in the DbContext, fortunately there is Effort a nice project on codeplex that starts to fill this.

对我来说,EF在单元测试方面的真正问题是DbContext中的DbConnection,幸运的是,在Codeplex上有一个很好的项目开始填充它。

Effort is a powerful tool that enables a convenient way to create automated tests for Entity Framework based applications. It is basically an ADO.NET provider that executes all the data operations on a lightweight in-process main memory database instead of a traditional external database. It provides some intuitive helper methods too that make really easy to use this provider with existing ObjectContext or DbContext classes. A simple addition to existing code might be enough to create data driven tests that can run without the presence of the external database.

Effort是一个功能强大的工具,可以方便地为基于Entity Framework的应用程序创建自动化测试。它基本上是一个ADO.NET提供程序,它在轻量级进程内主数据库而不是传统的外部数据库上执行所有数据操作。它提供了一些直观的帮助方法,使得这个提供程序与现有的ObjectContext或DbContext类一起使用非常容易。对现有代码的简单添加可能足以创建可在没有外部数据库的情况下运行的数据驱动测试。

With this, you can leave your DbContext and DbSet as is and do your unit tests easily. The only drawback with this is the difference between Linq providers where some unit tests may pass with effort and not with the real backend.

有了这个,您可以保留DbContext和DbSet,并轻松进行单元测试。唯一的缺点是Linq提供商之间的差异,其中一些单元测试可能会通过努力而不是真正的后端。

UPDATE with EF7

使用EF7更新

I still maintain that IDbContext would be useless and the problem comes from the DbConnection.

我仍然认为IDbContext没用,问题来自DbConnection。

EF7 will not have an IDbContext either, in order to do unit testing they are now giving an in memory provider.

EF7也没有IDbContext,为了进行单元测试,他们现在提供内存提供程序。

You can see Rowan Miller doing a demo here: Modern Data Applications with Entity Framework 7

你可以看到Rowan Miller在这里做一个演示:带有Entity Framework 7的现代数据应用程序