【问题标题】:Where should EF Migrations go, my Class Library project or my ASP.NET project?EF 迁移应该去哪里,我的类库项目还是我的 ASP.NET 项目?
【发布时间】:2015-03-10 21:45:43
【问题描述】:

我的解决方案包含:

  • FooBarAsp,一个 asp 项目(为应用程序提供 UI)
  • FooBar,一个类库(应用程序)
  • FooBar.Tests,一个测试项目(测试应用程序)

FooBar 使用 EF 6 Code First,并包含多个模型和一个DataContext。 FooBarAsp 使用 Microsoft 的 Identity 框架进行用户身份验证,并具有 ApplicationDbContext。两种上下文都很好,并且按预期工作。 Global.asax.cs 应该执行MigrateDatabaseToLatestVersion(对吗?)。 FooBar.Tests 应该执行 DropCreateDatabaseAlways 并且不会关心迁移(对吗?)。

我应该在 FooBarAsp 还是 FooBar 中启用迁移?对于这两种情况?

在 FooBar 中运行 EnableMigrations(只是为了好玩)后,我的 __MigrationHistory 表包含两个 InitialCreate 行,一个具有 ContextKey=FooBar.Models.DataContext,另一个具有 ContextKey=FooBarAsp.Models.ApplicationDbContext。所以他们都已经被追踪了?如果是这样,(并且由于我没有启用自动迁移),我是否需要在 Global.asax.cs 中显式运行 both MigrateDatabaseToLatestVersion<DataContext>MigrateDatabaseToLatestVersion<ApplicationDbContext>


编辑

我为什么不想将ApplicationUser 移动到FooBar 并将ApplicationDbContext 合并到DataContext 中?

ASP 附带的股票ApplicationUser 是一个单独的实体(和单独的ApplicationDbContext,恰好指向同一个数据库)。 ASP 的ApplicationUser 和身份框架负责身份验证、注册、电子邮件验证、登录、注销、密码、密码强度、密码重置、两因素身份验证、cookie、会话、来自 facebook/google 等来源的外部登录。不知道也不关心这些。 FooBar 的Users 有一个用户名,ASP 的ApplicationUsers 有一个用户名。当用户登录时,我只是通过UserName查找Foobar的User,这就是登录的人。所以当我创建一个新的Blog(其中Blog是一个FooBar实体)时,作者是FooBar的@987654338 @(不是ApplicationUser)。最终结果是 FooBar 不是 Web/Desktop/Console/iPhone/Android 应用程序。它是一个库,任何这些东西都可以引用、与之交互并为其提供用户界面。关键是 FooBar 没有受到任何这些用户界面的污染或偏见。

所以我不想将ApplicationUser 移动到 FooBar,因为它来自 Microsoft.AspNet.Identity 命名空间,而 FooBar 不知道也不关心 ASP.NET(或 WPF 或任何接口) .

【问题讨论】:

  • 我不首先使用代码,但是,如何从 Web 项目中删除所有数据访问?把这些都放在一个单独的类库中?
  • 迁移特定于您的代码优先模型,而不是您的 ASP.NET 项目,因此它们应该在您的 FooBar 库中。假设您创建了另一个 ASP.NET 或 WPF 项目并引用了 FooBar。您仍然希望/需要可用的迁移。
  • @alexw 好点。我想知道我是否需要迁移 ASP 用户上下文..

标签: c# asp.net entity-framework entity-framework-migrations


【解决方案1】:

就像 John 在他的评论中所说的那样,将所有 EF 代码移动到一个单独的类库中可能会为您提供很好的服务。我通常为新的解决方案创建 Web、Domain、DataAccess 和 Test 项目,并在必要时将它们进一步拆分。这为您提供了一些清晰、基本的关注点分离。 Visual Studio Web 项目模板不提供此功能,因为它被设计为在单个项目中自包含。

Visual Studio 的 Web 模板是小型项目的良好起点,但随着项目的发展,它很快就会变得一团糟。将网站(或多或少是您的表示层)、域模型和业务逻辑以及数据访问全部放在同一个项目中并不是特别好的做法。通过在 Web 应用程序中留下您的用户模型和单独的 DbContext 来将它们部分分开可能会更加混乱 IMO,特别是如果您的 ApplicationUsers 将参与与您的域类库中的模型的关系。

我建议将您的 ApplicationUser 移动到包含您的域模型的类库中,并将您的 ApplicationDbContext 移动到 DataAccess 类库中。您可以更进一步,毫不费力地将两个 DbContexts 合并为一个,除非您怀疑项目将增长到足以需要多个 DbContexts。到那时,您的 Migrations 应该放在哪里就变得非常明显了。除非您尝试将其抽象出来,否则您的 Initializer 将始终进入应用程序,在您的情况下是 FooBarAsp,因此您正确地认为 Global.asax 是设置它的地方。

然而,如果这听起来对您没有吸引力,并且您希望保持当前的项目结构,我认为您最好为 DbContexts 配置迁移为了一致性。那时,您的 Web 项目 (FooBarAsp) 中有一组迁移,用于继承自 IdentityDbContextApplicationDbContext 和驻留在您的类库 (FooBar) 中的另一组迁移。两者都需要您的 Web 项目的 Global.asax.cs 中的初始化程序。

根据 OP 的更新进行编辑:我可以看到您希望将 ASP.NET 相关引用排除在域层之外的原因。如果不将用户模型分成两部分,基本上是不可能防止这种情况发生的。 This is something I asked about when VS2013 was still pre-RTM 并没有得到满意的答案,因为目前不可能有一个用户模型与不引入某些 ASP.NET 相关程序集的 Identity 一起使用。但是,在某种类似的情况下,DbGeography 类型可能是一个非常有用的类型,可以包含在您的域层中,但是如果不拉入与实体框架相关的程序集,就不可能使用它。这实际上归结为权衡利弊并选择两个弊端中较小的一个 - 在何时何地应用设计模式时要务实。

也就是说,如果您确实想在 Web 应用程序中将 DbContexts 和 ApplicationUser 分开,我建议您从应用程序用户中提取所有无关字段 - 实际上,只需使用 IdentityUser类本身而不是子类化它,因为您将纯粹将其用于身份验证和授权。但是,我相信您仍然需要为两种上下文启用迁移并研究如何使用 multiple contexts per database with EF6,这在 EF5 中是不可能的。

【讨论】:

  • 查看我的编辑以响应您的第一个建议。 (ApplicationUsers 不参与与我的域类库中的模型的关系。)
  • PS 我真的很感谢你在回答中的想法。
猜你喜欢
  • 2021-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-13
  • 1970-01-01
  • 2020-07-02
  • 1970-01-01
  • 2013-05-18
相关资源
最近更新 更多