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-database
和 Enable-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; }
}
}
到目前为止,这就是您所做的差不多了但是,请注意两点:
BaseContext
公开一个采用连接字符串(或连接字符串键名)的构造函数 - 这会传递到 DbContext
中的相同构造函数
- 派生上下文将键名 "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
它会将 SystemUser
和 Order
发布到一个新数据库(在我的示例中称为 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
.
我们有一个项目,其中有多个解决方案都共享一个公共核心库。我们的核心库具有我们所有的默认实体、数据上下文和适用于此上下文的实用程序。我想让 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-database
和 Enable-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; }
}
}
到目前为止,这就是您所做的差不多了但是,请注意两点:
BaseContext
公开一个采用连接字符串(或连接字符串键名)的构造函数 - 这会传递到DbContext
中的相同构造函数
- 派生上下文将键名 "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
它会将 SystemUser
和 Order
发布到一个新数据库(在我的示例中称为 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
.