两个不同的 EF dbContexts 在同一个单元测试中不起作用
Two different EF dbContexts are not working in same unit test
我正在使用:
英孚 6.2,
视觉工作室 2017,
nUnit 2.6.3.13283(单元测试),
Unity 5.8.5(作为 IoC)。
当我想在同一个单元测试中测试两个不同的 DbContext 时出现问题。
第一个上下文:
public class MsSqlConfiguration : System.Data.Entity.DbConfiguration
{
public MsSqlConfiguration()
{
this.SetDefaultConnectionFactory(new System.Data.Entity.Infrastructure.SqlConnectionFactory());
this.SetProviderServices("System.Data.SqlClient", System.Data.Entity.SqlServer.SqlProviderServices.Instance);
}
}
[DbConfigurationType(typeof(MsSqlConfiguration))]
public class SqlDbContext: DbContext
{
public SqlDbContext(string connectonString) : base(connectonString)
{}
public DbSet<SomeClass> SomeField { get; set; }
}
第二个上下文:
public class SQLiteProviderInvariantName : IProviderInvariantName
{
public static readonly SQLiteProviderInvariantName Instance = new SQLiteProviderInvariantName();
private SQLiteProviderInvariantName() { }
public const string ProviderName = "System.Data.SQLite.EF6";
public string Name { get { return ProviderName; } }
}
class SQLiteDbDependencyResolver : IDbDependencyResolver
{
public object GetService(Type type, object key)
{
if (type == typeof(IProviderInvariantName)) return SQLiteProviderInvariantName.Instance;
if (type == typeof(DbProviderFactory)) return SQLiteProviderFactory.Instance;
return SQLiteProviderFactory.Instance.GetService(type);
}
public IEnumerable<object> GetServices(Type type, object key)
{
var service = GetService(type, key);
if (service != null) yield return service;
}
}
public class SQLiteConfiguration : System.Data.Entity.DbConfiguration
{
public SQLiteConfiguration()
{
AddDependencyResolver(new SQLiteDbDependencyResolver());
SetProviderFactory("System.Data.SQLite", SQLiteFactory.Instance);
SetProviderFactory("System.Data.SQLite.EF6", SQLiteProviderFactory.Instance);
SetProviderServices("System.Data.SQLite", (DbProviderServices)SQLiteProviderFactory.Instance.GetService(typeof(DbProviderServices)));
}
}
[DbConfigurationType(typeof(SQLiteConfiguration))]
public class SqlDbContext : DbContext
{
public SqlDbContext (string connectonString) : base(connectonString)
{
}
public DbSet<SomeClass> SomeField{ get; set; }
}
单元测试:
[TestFixture]
class DbContextIntegrationTests
{
[Test]
public void CanReadFromMsSqlDatabase()
{
using (var context = IocContainer.Instance.Resolve<MsSqlDbContext>(someConnString))
{
Assert.DoesNotThrow(() => context.SomeField.FirstOrDefault());
}
}
[Test]
public void CanReadFromSqliteDatabase()
{
using (var context2 = IocContainer.Instance.Resolve<SqliteDbContext>(someConnString2))
{
Assert.DoesNotThrow(() => context2.Somefield.FirstOrDefault());
}
}
}
当我通过传递连接字符串分别实例化上述上下文时 - 它们都工作正常。
但是,如果它们是同一单元测试的一部分 class - 它们就不能 运行。
第一个上下文将它的提供者设置为默认值(比如 SQL 一个),下一个 DbContext(比如 SQLite 一个)不能设置它的提供者。
如果 MS SQL dbcontext 先行,然后 SQLite dbcontext 得到下一个异常:
System.InvalidOperationException: 'Unable to complete operation. The
supplied SqlConnection does not specify an initial catalog or
AttachDBFileName.'
如果 SQLite 在前,则 MS SQL 上下文获取:
System.InvalidOperationException: 'The store type 'date' could not be found in the SQLite provider manifest'
我只是想知道我在这里遗漏了什么。
是否特定于 nUnit(某些缓存)。
或者它确实是 EF 提供程序的一些常见位置,只能设置一次。
我根本没有使用 App.config - 只是从某个保存的地方传递配置字符串。
@Bit @programtreasures
找到答案了。
根本原因是 EF 无法同时处理多个 DBConfiguration(可能在内存中),即使它们是不同 DbContext 的一部分。
这里有更多详细信息:
https://msdn.microsoft.com/en-us/data/jj680699
所以我刚刚创建了一个公共上下文:
using System.Data.Entity.Core.Common;
using System.Data.SQLite;
using System.Data.SQLite.EF6;
namespace ClassLibrary1
{
public class commonConfig : System.Data.Entity.DbConfiguration
{
public commonConfig()
{
SetDefaultConnectionFactory(new System.Data.Entity.Infrastructure.SqlConnectionFactory());
SetProviderServices("System.Data.SqlClient", System.Data.Entity.SqlServer.SqlProviderServices.Instance);
SetProviderFactory("System.Data.SQLite", SQLiteFactory.Instance);
SetProviderServices("System.Data.SQLite", (DbProviderServices)SQLiteProviderFactory.Instance.GetService(typeof(DbProviderServices)));
SetProviderFactory("System.Data.SQLite.EF6", SQLiteProviderFactory.Instance);
}
}
}
和 MS SQL 数据库上下文:
using System.Data.Entity;
using System.Data.SqlClient;
namespace ClassLibrary1
{
[DbConfigurationType(typeof(commonConfig))]
public class MsSqlDbContext : DbContext
{
public MsSqlDbContext(SqlConnection existingConnection,
bool contextOwnsConnection) : base(existingConnection, contextOwnsConnection)
{
DbConfiguration.SetConfiguration(new commonConfig());
}
public DbSet<SomeTableEntity> SomeTable { get; set; }
}
}
和 SqliteDbContext:
using System.Data.Entity;
using System.Data.SQLite;
namespace ClassLibrary1
{
[DbConfigurationType(typeof(commonConfig))]
public class SqliteDbContext : DbContext
{
public SqliteDbContext(SQLiteConnection existingConnection,
bool contextOwnsConnection) : base(existingConnection, contextOwnsConnection)
{
DbConfiguration.SetConfiguration(new commonConfig());
}
public DbSet<SomeDbTableEntity> SomeTable { get; set; }
}
}
然后我可以 运行 像下面这样的单元测试:
[TestMethod]
public void TestMethod()
{
using (var context1 = new SqliteDbContext(new SQLiteConnection(
@"C:\db.sqlite"), true
))
{
Console.WriteLine("SQLITE" + Environment.NewLine);
Console.Write(context1.SomeTable.FirstOrDefault().SomeRecord);
Console.WriteLine(Environment.NewLine);
}
using (var context2 =
new MsSqlDbContext(
new SqlConnection(@"Data Source=localhost;Initial Catalog=SomeDatabase;Integrated Security=True")
, true)
)
{
Console.WriteLine("MS SQL" + Environment.NewLine);
Console.Write(context2.SomeTable.FirstOrDefault().SomeRecord);
Console.WriteLine(Environment.NewLine);
}
}
我正在使用: 英孚 6.2, 视觉工作室 2017, nUnit 2.6.3.13283(单元测试), Unity 5.8.5(作为 IoC)。
当我想在同一个单元测试中测试两个不同的 DbContext 时出现问题。
第一个上下文:
public class MsSqlConfiguration : System.Data.Entity.DbConfiguration
{
public MsSqlConfiguration()
{
this.SetDefaultConnectionFactory(new System.Data.Entity.Infrastructure.SqlConnectionFactory());
this.SetProviderServices("System.Data.SqlClient", System.Data.Entity.SqlServer.SqlProviderServices.Instance);
}
}
[DbConfigurationType(typeof(MsSqlConfiguration))]
public class SqlDbContext: DbContext
{
public SqlDbContext(string connectonString) : base(connectonString)
{}
public DbSet<SomeClass> SomeField { get; set; }
}
第二个上下文:
public class SQLiteProviderInvariantName : IProviderInvariantName
{
public static readonly SQLiteProviderInvariantName Instance = new SQLiteProviderInvariantName();
private SQLiteProviderInvariantName() { }
public const string ProviderName = "System.Data.SQLite.EF6";
public string Name { get { return ProviderName; } }
}
class SQLiteDbDependencyResolver : IDbDependencyResolver
{
public object GetService(Type type, object key)
{
if (type == typeof(IProviderInvariantName)) return SQLiteProviderInvariantName.Instance;
if (type == typeof(DbProviderFactory)) return SQLiteProviderFactory.Instance;
return SQLiteProviderFactory.Instance.GetService(type);
}
public IEnumerable<object> GetServices(Type type, object key)
{
var service = GetService(type, key);
if (service != null) yield return service;
}
}
public class SQLiteConfiguration : System.Data.Entity.DbConfiguration
{
public SQLiteConfiguration()
{
AddDependencyResolver(new SQLiteDbDependencyResolver());
SetProviderFactory("System.Data.SQLite", SQLiteFactory.Instance);
SetProviderFactory("System.Data.SQLite.EF6", SQLiteProviderFactory.Instance);
SetProviderServices("System.Data.SQLite", (DbProviderServices)SQLiteProviderFactory.Instance.GetService(typeof(DbProviderServices)));
}
}
[DbConfigurationType(typeof(SQLiteConfiguration))]
public class SqlDbContext : DbContext
{
public SqlDbContext (string connectonString) : base(connectonString)
{
}
public DbSet<SomeClass> SomeField{ get; set; }
}
单元测试:
[TestFixture]
class DbContextIntegrationTests
{
[Test]
public void CanReadFromMsSqlDatabase()
{
using (var context = IocContainer.Instance.Resolve<MsSqlDbContext>(someConnString))
{
Assert.DoesNotThrow(() => context.SomeField.FirstOrDefault());
}
}
[Test]
public void CanReadFromSqliteDatabase()
{
using (var context2 = IocContainer.Instance.Resolve<SqliteDbContext>(someConnString2))
{
Assert.DoesNotThrow(() => context2.Somefield.FirstOrDefault());
}
}
}
当我通过传递连接字符串分别实例化上述上下文时 - 它们都工作正常。
但是,如果它们是同一单元测试的一部分 class - 它们就不能 运行。 第一个上下文将它的提供者设置为默认值(比如 SQL 一个),下一个 DbContext(比如 SQLite 一个)不能设置它的提供者。
如果 MS SQL dbcontext 先行,然后 SQLite dbcontext 得到下一个异常:
System.InvalidOperationException: 'Unable to complete operation. The supplied SqlConnection does not specify an initial catalog or AttachDBFileName.'
如果 SQLite 在前,则 MS SQL 上下文获取:
System.InvalidOperationException: 'The store type 'date' could not be found in the SQLite provider manifest'
我只是想知道我在这里遗漏了什么。 是否特定于 nUnit(某些缓存)。 或者它确实是 EF 提供程序的一些常见位置,只能设置一次。
我根本没有使用 App.config - 只是从某个保存的地方传递配置字符串。
@Bit @programtreasures
找到答案了。 根本原因是 EF 无法同时处理多个 DBConfiguration(可能在内存中),即使它们是不同 DbContext 的一部分。
这里有更多详细信息: https://msdn.microsoft.com/en-us/data/jj680699
所以我刚刚创建了一个公共上下文:
using System.Data.Entity.Core.Common;
using System.Data.SQLite;
using System.Data.SQLite.EF6;
namespace ClassLibrary1
{
public class commonConfig : System.Data.Entity.DbConfiguration
{
public commonConfig()
{
SetDefaultConnectionFactory(new System.Data.Entity.Infrastructure.SqlConnectionFactory());
SetProviderServices("System.Data.SqlClient", System.Data.Entity.SqlServer.SqlProviderServices.Instance);
SetProviderFactory("System.Data.SQLite", SQLiteFactory.Instance);
SetProviderServices("System.Data.SQLite", (DbProviderServices)SQLiteProviderFactory.Instance.GetService(typeof(DbProviderServices)));
SetProviderFactory("System.Data.SQLite.EF6", SQLiteProviderFactory.Instance);
}
}
}
和 MS SQL 数据库上下文:
using System.Data.Entity;
using System.Data.SqlClient;
namespace ClassLibrary1
{
[DbConfigurationType(typeof(commonConfig))]
public class MsSqlDbContext : DbContext
{
public MsSqlDbContext(SqlConnection existingConnection,
bool contextOwnsConnection) : base(existingConnection, contextOwnsConnection)
{
DbConfiguration.SetConfiguration(new commonConfig());
}
public DbSet<SomeTableEntity> SomeTable { get; set; }
}
}
和 SqliteDbContext:
using System.Data.Entity;
using System.Data.SQLite;
namespace ClassLibrary1
{
[DbConfigurationType(typeof(commonConfig))]
public class SqliteDbContext : DbContext
{
public SqliteDbContext(SQLiteConnection existingConnection,
bool contextOwnsConnection) : base(existingConnection, contextOwnsConnection)
{
DbConfiguration.SetConfiguration(new commonConfig());
}
public DbSet<SomeDbTableEntity> SomeTable { get; set; }
}
}
然后我可以 运行 像下面这样的单元测试:
[TestMethod]
public void TestMethod()
{
using (var context1 = new SqliteDbContext(new SQLiteConnection(
@"C:\db.sqlite"), true
))
{
Console.WriteLine("SQLITE" + Environment.NewLine);
Console.Write(context1.SomeTable.FirstOrDefault().SomeRecord);
Console.WriteLine(Environment.NewLine);
}
using (var context2 =
new MsSqlDbContext(
new SqlConnection(@"Data Source=localhost;Initial Catalog=SomeDatabase;Integrated Security=True")
, true)
)
{
Console.WriteLine("MS SQL" + Environment.NewLine);
Console.Write(context2.SomeTable.FirstOrDefault().SomeRecord);
Console.WriteLine(Environment.NewLine);
}
}