Code First 和 DBContext 的多态性

Polymorphism with Code First and DBContext

我们有一个项目,其中有多个解决方案都共享一个公共核心库。我们的核心库具有我们所有的默认实体、数据上下文和适用于此上下文的实用程序。我想让 Web 项目扩展核心上下文,但我似乎总是没有迁移或多个数据库。本质上,我希望能够拥有

namespace Core
{
    public class BaseContext : DbContext
    {
        DBSet<SomeCoreEntity> CoreEntities {get;set;}
    }
}

然后有

namespace Web
{
    public class DerivedContext : Core.BaseContext
    {
        DBSet<SomeNewEntity> NewEntities {get;set;}
    }
}

从这里开始,我希望核心能够拥有

baseContextInstance.CoreEntities

derivedContextInstance.CoreEntites

引用相同的 table,但派生的上下文也可以访问 NewEntite。这样做的正确方法是什么?它是否需要 web.config 中的某些特殊内容,也许是 DatabaseInitializerForType?我环顾四周,找不到任何关于如何执行此操作的好文档。

因此,如果您确保 Derived 上下文和基本上下文实质上使用相同的 ConnectionString 键,这看起来是可能的。您可以让他们使用不同的密钥,但这只会导致您需要维护的重复。

注意: 我正在使用包管理器中的 update-databaseEnable-Migrations 命令。其他部署过程的一般原理应该相同,但我没有测试过。

首先,创建您的基础上下文(以及关联的 DbSet 类):

namespace Core
{
    public partial class BaseContext : DbContext
    {
        public BaseContext()
        {

        }

        public BaseContext(string connectionString)
            : base(connectionString)
        {

        }

        public DbSet<SystemUser> SystemUser { get; set; }
    }

    public partial class SystemUser
    {
        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }

        public string Forename { get; set; }
        public string Surname { get; set; }
    }
}

接下来,创建派生上下文(使用新的 类):

namespace Web
{
    public class DerivedContext : Core.BaseContext
    {
        public DerivedContext()
            : base("BaseContext")
        {

        }

        public DbSet<Order> Order { get; set; }
    }

    public class Order
    {
        public int Id { get; set; }
        public double Quantity { get; set; }
        public string Item { get; set; }
    }
}

到目前为止,这就是您所做的差不多了但是,请注意两点:

  1. BaseContext 公开一个采用连接字符串(或连接字符串键名)的构造函数 - 这会传递到 DbContext
  2. 中的相同构造函数
  3. 派生上下文将键名 "BaseContext" 向下传递给 BaseContext

现在,将连接字符串条目添加到 Web 项目中的 .config 文件,键名 BaseContext 和适当的连接字符串。

<connectionStrings>
    <add name="BaseContext" connectionString="Data Source=.;Initial Catalog=TestDb;Integrated Security=SSPI;" providerName="System.Data.SqlClient" />
</connectionStrings>

通过在包管理器控制台中输入以下内容来添加到 Web 项目的迁移(确保您已从下拉列表中选择了 Web 项目):

Enable-Migrations

进入创建的Migration文件,在构造函数中将AutomaticMigrations改为true

public Configuration()
{
    AutomaticMigrationsEnabled = true;
}

现在,当您从 Web 项目发布时,在 PM 控制台中使用以下内容:

Update-Database

它会将 SystemUserOrder 发布到一个新数据库(在我的示例中称为 TestDb)。


用法:

如果您检查您的数据库,您会注意到它已成功创建 SystemUsers 和 Orders 表。

如果您 运行 来自您的应用程序的以下代码:

using (var ctxt = new Core.BaseContext())
{
    var user1 = new Core.SystemUser()
    {
        Forename = "Obsidian",
        Surname = "Phoenix"
    };

    ctxt.SystemUser.Add(user1);

    ctxt.SaveChanges();
}

using (var ctxt = new DerivedContext())
{
    var user2 = new Core.SystemUser()
    {
        Forename = "John",
        Surname = "Doe"
    };

    ctxt.SystemUser.Add(user2);

    ctxt.SaveChanges();


    var users = ctxt.SystemUser.ToList();

    users.ForEach(u => Debug.WriteLine(string.Format("{0} {1}", u.Forename, u.Surname)));

    var order = new Order()
    {
        Id = 1,
        Item = "Test Item",
        Quantity = 1
    };

    ctxt.Orders.Add(order);

    ctxt.SaveChanges();
}

你可以看到我可以同时使用 BaseContext DerivedContext 到 read/write 到 Systemuser,以及我可以使用 DerivedContext 到 read/write 到 Order.