我已经为每个客户构建了一个具有Core解决方案和Custom解决方案的系统。 Core拥有自己的dbcontext,每个海关都有自己的dbcontext用于客户特定的表。 自定义解决方案引用了Core解决方案dll。 Core解决方案在插件架构中动态加载自定义dll。 由于Core和Custom有自己的dbcontext,每个都有自己的迁移文件。
一切都很好,除了一件事,我不能做一个linq查询加入Core表与自定义表。 (例如:在单个查询中将ProjectCustom与Project一起加入)。 我收到错误:
The specified LINQ expression contains references to queries that are associated with different contexts.
因此,为了允许查询从Core和Custom连接表,我想到另一条路径,其中Core定义基本抽象DbContext,而Custom继承自此dbcontext并添加其自定义表。所以我在运行时有一个dbcontext。
现在我的问题是,有什么办法可以在Core中安装迁移文件,还有另一组在Custom中定义的迁移文件?
我已经制定了一个可行的解决方案,其中所有迁移都在Custom解决方案中进行了维护。但是我不喜欢这样一个事实:如果我进行影响Core表的手动迁移,我必须手动将其传播到所有Custom解决方案。
我希望将影响Core表的迁移保留到Core解决方案中,并为海关进行另一组迁移。全部应用于相同的dbcontext,最终实现位于自定义解决方案中。
这可能吗?有没有办法为迁移文件配置某种提供程序?因此,我可以先应用Core解决方案中定义的迁移,然后使用相同的dbcontext从自定义应用迁移。
答案 0 :(得分:2)
让我们首先为Context的配置创建一个接口
public interface IDbContextRegistry
{
void Configure(DbModelBuilder builder);
}
在我的情况下,实现存在于每个单独的Context中,但在diff类中实现它将是很好的。
public class ContextA : DbContext, IDbContextRegistry
{
static ContextA()
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<ContextA, ConfigurationA>());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
Configure(modelBuilder);
}
public void Configure(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ModelA>();
}
}
internal sealed class ConfigurationA : DbMigrationsConfiguration<ContextA>
{
public ConfigurationA()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(ContextA context)
{
}
}
public class ModelA
{
public int Id { get; set; }
public string Name { get; set; }
}
和
public class ContextB : DbContext, IDbContextRegistry
{
static ContextB()
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<ContextB, ConfigurationB>());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
Configure(modelBuilder);
}
public void Configure(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ModelB>();
}
}
internal sealed class ConfigurationB : DbMigrationsConfiguration<ContextB>
{
public ConfigurationB()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(ContextB context)
{
}
}
public class ModelB
{
public int Id { get; set; }
public DateTimeOffset Date { get; set; }
}
稍后在您的主应用程序中创建一个将注册所有单个类型的上下文。
public class ContextJoin : DbContext
{
private readonly List<IDbContextRegistry> _registry = new List<IDbContextRegistry>();
public ContextJoin(params IDbContextRegistry[] registry)
{
_registry.AddRange(registry);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
foreach (var entry in _registry)
{
entry.Configure(modelBuilder);
}
}
}
并且瞧,每个实体都生活在ContextJoin中并准备使用。 例如:
class Program
{
static void Main(string[] args)
{
ContextA ctxA = new ContextA();
ctxA.Set<ModelA>().Add(new ModelA());
ctxA.SaveChanges();
ContextB ctxB = new ContextB();
ctxB.Set<ModelB>().Add(new ModelB());
ctxB.SaveChanges();
ContextJoin ctxJoin = new ContextJoin(ctxA, ctxB);
ctxJoin.Set<ModelB>().Add(new ModelB());
ctxJoin.Set<ModelA>().Add(new ModelA());
ctxJoin.SaveChanges();
var crossQuery = ctxJoin.Set<ModelA>().Join(
ctxJoin.Set<ModelB>(), t => t.Id, t => t.Id, (a, b) => new
{
a.Name,
b.Date
}).ToList();
crossQuery.ForEach(t => Console.WriteLine($"Name: {t.Name}, Date: {t.Date}"));
}
}
希望这有帮助!