Jos*_*ltz 193 entity-framework ef-code-first dbcontext entity-framework-4.3
我的印象是DbContext意味着代表你的数据库,因此,如果你的应用程序使用一个数据库,你只需要一个DbContext.但是,有些同事希望将功能区域分解为单独的DbContext类.我相信这来自一个好地方 - 希望保持代码清洁 - 但它似乎不稳定.我的直觉告诉我这是一个坏主意,但不幸的是,我的直觉并不是设计决策的充分条件.
所以我正在寻找A)为什么这可能是一个坏主意的具体例子,或B)保证这一切都很好.
Lad*_*nka 159
您可以为单个数据库设置多个上下文.例如,如果您的数据库包含多个数据库模式,并且您希望将它们作为单独的自包含区域进行处理,那么它可能很有用.
问题是当您想首先使用代码创建数据库时 - 应用程序中只有单个上下文可以做到这一点.这方面的技巧通常是一个附加的上下文,其中包含仅用于创建数据库的所有实体.只包含实体子集的真实应用程序上下文必须将数据库初始化程序设置为null.
在使用多种上下文类型时,您会看到其他问题 - 例如共享实体类型以及它们从一个上下文传递到另一个上下文等.一般情况下,它可以使您的设计更清晰,并将不同的功能区域分开,但它有它的另外复杂的成本.
Jul*_*man 51
这个帖子刚刚在StackOverflow上冒出来,所以我想提供另一个"B)保证这一切都很好":)
我通过DDD Bounded Context模式正是这样做的.我在我的书"编程实体框架:DbContext"中写过这篇文章,它是我在Pluralsight课程中的一个50分钟模块的重点 - > http://pluralsight.com/training/Courses/TableOfContents/efarchitecture
Fra*_*nia 48
我会反对这个想法,用现实世界的经验来支持我的投票.
我被带到一个大型应用程序,该应用程序有五个上下文用于单个数据库.最后,我们最终删除了除了一个之外的所有上下文 - 恢复到单个上下文.
起初,多个上下文的想法似乎是一个好主意.我们可以将数据访问分离到域中,并提供几个干净的轻量级上下文.听起来像DDD,对吧?这将简化我们的数据访问.另一个论点是性能,因为我们只访问我们需要的上下文.
但实际上,随着我们的应用程序的发展,我们的许多表都在各种环境中共享关系.例如,在上下文1中对表A的查询也需要在上下文2中连接表B.
这给我们留下了几个糟糕的选择.我们可以在各种上下文中复制表.我们试过这个.这创建了几个映射问题,包括要求每个实体具有唯一名称的EF约束.所以我们在不同的上下文中得到了名为Person1和Person2的实体.有人可能会说这是我们糟糕的设计,但尽管我们付出了最大的努力,但这就是我们的应用程序在现实世界中实际增长的方式.
我们还尝试查询两个上下文以获取我们需要的数据.例如,我们的业务逻辑将从上下文1查询其所需内容的一半,而从上下文2查询另一半.这有一些重大问题.我们不得不针对单个上下文执行一个查询,而是必须跨不同的上下文执行多个查询.这有一个真正的性能损失.
最后,好消息是很容易剥离多个上下文.上下文旨在成为轻量级对象.所以我认为性能不是多个上下文的好参数.在几乎所有情况下,我认为单个上下文更简单,更简单,并且可能性能更好,并且您不必实施一系列解决方案来使其工作.
我想到了一种情况,其中多个上下文可能有用.可以使用单独的上下文来修复实际包含多个域的数据库的物理问题.理想情况下,上下文与域一对一,与数据库一对一.换句话说,如果一组表不以任何方式与在一个给定的数据库中的其他表,他们或许应该被划到了一个单独的数据库.我意识到这并不总是实用的.但是,如果一组表是如此不同,你会感觉很舒服分离到一个单独的数据库(但不选择),那么我可以看到的情况下,使用一个单独的上下文,但仅仅是因为居然有两个不同领域.
我对你的想法很感兴趣.
Mar*_*tin 42
通过设置默认架构来区分上下文
在EF6中,您可以拥有多个上下文,只需在派生类的OnModelCreating方法中指定默认数据库模式的名称DbContext(Fluent-API配置所在的位置).这将适用于EF6:
public partial class CustomerModel : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("Customer");
// Fluent API configuration
}
}
Run Code Online (Sandbox Code Playgroud)
此示例将使用"Customer"作为数据库表的前缀(而不是"dbo").更重要的是,它也会在__MigrationHistory表格前加上前缀,例如Customer.__MigrationHistory.因此,您可以__MigrationHistory在一个数据库中拥有多个表,每个表对应一个上下文.因此,您为一个上下文所做的更改不会与另一个上下文混淆.
添加迁移时,请DbMigrationsConfiguration在add-migration命令中将参数类的完全限定名称(派生自)指定为参数:
add-migration NAME_OF_MIGRATION -ConfigurationTypeName FULLY_QUALIFIED_NAME_OF_CONFIGURATION_CLASS
Run Code Online (Sandbox Code Playgroud)
关于上下文密钥的简短说明
根据这篇MSDN文章" 章节 - 针对同一数据库的多个模型 ",即使只有一个MigrationHistory表存在,EF 6也可能会处理这种情况,因为在表中有一个ContextKey列来区分迁移.
但是,我更喜欢MigrationHistory通过指定默认架构来拥有多个表,如上所述.
使用单独的迁移文件夹
在这种情况下,您可能还希望在项目中使用不同的"迁移"文件夹.您可以DbMigrationsConfiguration使用MigrationsDirectory属性相应地设置派生类:
internal sealed class ConfigurationA : DbMigrationsConfiguration<ModelA>
{
public ConfigurationA()
{
AutomaticMigrationsEnabled = false;
MigrationsDirectory = @"Migrations\ModelA";
}
}
internal sealed class ConfigurationB : DbMigrationsConfiguration<ModelB>
{
public ConfigurationB()
{
AutomaticMigrationsEnabled = false;
MigrationsDirectory = @"Migrations\ModelB";
}
}
Run Code Online (Sandbox Code Playgroud)
摘要
总而言之,您可以说一切都是完全分开的:上下文,项目中的迁移文件夹和数据库中的表.
我会选择这样一个解决方案,如果有一组实体是一个更大的主题的一部分,但没有相互关联(通过外键).
如果实体组彼此没有任何关系,我会为每个实体创建一个单独的数据库,并在不同的项目中访问它们,可能每个项目中只有一个上下文.
提醒:如果您组合了多个上下文,请确保将各种功能中的所有功能粘贴RealContexts.OnModelCreating()到单个中CombinedContext.OnModelCreating().
我只是浪费时间寻找为什么我的级联删除关系没有被保留只是为了发现我没有将modelBuilder.Entity<T>()....WillCascadeOnDelete();我的真实上下文中的代码移植到我的组合上下文中.
简单的例子来实现以下目的:
ApplicationDbContext forumDB = new ApplicationDbContext();
MonitorDbContext monitor = new MonitorDbContext();
Run Code Online (Sandbox Code Playgroud)
只需在主上下文中定义属性:(用于创建和维护DB)注意:只需使用protected :(实体不在此处公开)
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("QAForum", throwIfV1Schema: false)
{
}
protected DbSet<Diagnostic> Diagnostics { get; set; }
public DbSet<Forum> Forums { get; set; }
public DbSet<Post> Posts { get; set; }
public DbSet<Thread> Threads { get; set; }
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
Run Code Online (Sandbox Code Playgroud)
MonitorContext:在这里公开单独的实体
public class MonitorDbContext: DbContext
{
public MonitorDbContext()
: base("QAForum")
{
}
public DbSet<Diagnostic> Diagnostics { get; set; }
// add more here
}
Run Code Online (Sandbox Code Playgroud)
诊断模型:
public class Diagnostic
{
[Key]
public Guid DiagnosticID { get; set; }
public string ApplicationName { get; set; }
public DateTime DiagnosticTime { get; set; }
public string Data { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
如果您愿意,可以将所有实体标记为主ApplicationDbContext中的受保护,然后根据需要为每个模式分隔创建其他上下文.
它们都使用相同的连接字符串,但它们使用单独的连接,因此不要交叉事务并注意锁定问题.通常你的设计分离,所以这不应该发生.
当我遇到这个设计时,我的直觉告诉我同样的事情。
我正在开发一个代码库,其中一个数据库有三个 dbContext。3 个 dbcontext 中的 2 个依赖于 1 个 dbcontext 的信息,因为它提供管理数据。此设计对查询数据的方式施加了限制。我遇到了这个问题,您无法跨 dbcontexts 加入。相反,您需要做的是查询两个单独的 dbcontext,然后在内存中进行联接或迭代两者以获取两者的组合作为结果集。问题在于,您现在不是查询特定结果集,而是将所有记录加载到内存中,然后对内存中的两个结果集进行联接。它确实可以减慢速度。
我会问这个问题“只是因为你可以,不是吗? ”
请参阅这篇文章,了解我遇到的与此设计相关的问题。
指定的 LINQ 表达式包含对与不同上下文关联的查询的引用
灵感来自 [@JulieLerman 的 DDD MSDN Mag 文章 2013][1]
public class ShippingContext : BaseContext<ShippingContext>
{
public DbSet<Shipment> Shipments { get; set; }
public DbSet<Shipper> Shippers { get; set; }
public DbSet<OrderShippingDetail> Order { get; set; } //Orders table
public DbSet<ItemToBeShipped> ItemsToBeShipped { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Ignore<LineItem>();
modelBuilder.Ignore<Order>();
modelBuilder.Configurations.Add(new ShippingAddressMap());
}
}
Run Code Online (Sandbox Code Playgroud)
public class BaseContext<TContext>
DbContext where TContext : DbContext
{
static BaseContext()
{
Database.SetInitializer<TContext>(null);
}
protected BaseContext() : base("DPSalesDatabase")
{}
}
Run Code Online (Sandbox Code Playgroud)
“如果您正在进行新的开发并且希望让 Code First 根据您的类创建或迁移您的数据库,您将需要使用 DbContext 创建一个“超级模型”,其中包含所有类和关系构建代表数据库的完整模型。但是,此上下文不能从 BaseContext 继承。” 杰伦
| 归档时间: |
|
| 查看次数: |
96132 次 |
| 最近记录: |