我制作了一个使用Entity Framework Core处理持久性的库。 面向SQL Server数据库的Web API使用它。 此外,我针对SQLite数据库进行了测试(单元测试)。
我使用配置文件以简单的方式完成了该任务。因此,在扩展DBContext的类中,我使用以下内容实现了OnConfiguring:
if(isSqlServer) //don't mind where it comes from, it works fine
optionsBuilder.UseSqlServer(connectionString);
else
optionsBuilder.UseSqlite(connectionString);
它似乎工作正常,但效果不理想。假设我有这个项目:
由于UseSqlite方法是Microsoft.EntityFrameworkCore.Sqlite包的类中的静态扩展方法,并且类似地,方法UseSqlServer是Microsoft.EntityFrameworkCore.SqlServer包的类中的静态扩展方法,有两件事很麻烦我。
首先,我必须在三个项目中包括两个依赖项,以避免在运行时出现错误“ System.IO.FileNotFoundException:无法加载文件或程序集Microsoft.EntityFrameworkCore.SqlServer(...)”。
第二,如果需要支持新的DBMS(Oracle,MySQL),则必须在这三个项目中包括新的依赖项。
我希望建立一个方案,其中项目PersistentLayer将不具有那些依赖关系,而PersistentLayerTests将仅依赖于Microsoft.EntityFrameworkCore.Sqlite和WebAPI将仅依赖于Microsoft.EntityFrameworkCore.SqlServer。
还有另一种方法来配置连接上下文以解耦这些程序包依赖性吗?
注意:
答案 0 :(得分:2)
您只需要让 DbContext 的用户(PersistenceLayerTests和WebApi项目)负责配置它,而不是 DbContext 本身。
DbContext provides a constructor接受 DbContextOptions 。您需要公开此构造函数:
public class MyDbContext : DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> options) : base(options) { }
// ...
}
然后,您可以执行以下操作:
var optionsBuilder = new DbContextOptionsBuilder<MyDbContext>();
if (isSqlServer) //don't mind where it comes from, it works fine
optionsBuilder.UseSqlServer(connectionString);
else
optionsBuilder.UseSqlite(connectionString);
using (var context = new MyDbContext(optionsBuilder.Options))
{
// ...
}
答案 1 :(得分:2)
这似乎有些矫kill过正,但是,在这种情况下,基本策略是放置一个公共界面,并将其分隔在不同的项目中。不确定这是否是这种情况的最佳解决方案。
然后,不同的项目是独立的(除了通用界面之外),并且随着时间的推移可以轻松扩展。
关键部分是在您的主项目中仅引用接口组件,而不引用其中之一。如果要避免使用FileNotFoundException
,则必须在运行时加载混凝土(装配体):此外:您需要一种机制来拾取合适的(通常称为factory
)。
让我们考虑一下其中有3种(sql,sqllite和oracle)的情况:
要做的第一件事是创建一个通用接口来与适当的Db enginge通信,例如:
//separate assembly
public interface IDbEningeSelector
{
//added the option builder for simplicity: one could do better.
void Configure(string connectionString,IOptionsBuilder optionsBuilder);
}
接下来,只需为具体的实现创建3个独立的项目,一个sql-lite,一个sql和一个oracle。
下一步:在三个项目中创建一个实现此目的的类:
//3 of these.
public class SqlEnging : IDbEngineSelector
{
public void Configure(string connectionString,IOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(connectionString);
}
}
好的,现在您可以选择其中之一。
//the "thing"
IDbEngineSelector selector = null;
selector = //resolve through factory, possibly based on a flag.
selector.Configure(connectionString, optionsBuilder);
基本上,您已经完成了可扩展的,动态引用的数据库提供程序系统。
对于动态程序集解析器,您需要按照本文中的描述进行加载: https://www.codeproject.com/Articles/1194332/Resolving-Assemblies-in-NET-Core
这实际上将在运行时加载依赖项,为此,我建议保留一个特殊路径以放置这些程序集。
我省略了工厂实现的详细信息,我需要首先检查在.net Core中执行该操作的正确方法,等等...