- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试制作一些在我的存储库层中使用 EF 的模块类库 API。为了使其中的任何一个起作用,我需要在每个类库中有一个 dbcontext 类。但是当我需要在每个模块中引用一个类时会发生什么?例如,我有一个用户模块,其数据库上下文包括:
然后我有一个位置模块,其中包括:
然后说第三个设备模块,它有:
后两者仍然需要对用户的引用,这几乎是每个模块不可或缺的一部分。但是我不能将两个单独的用户类添加到指向同一个数据库的两个上下文中,它们可能会变得不同步。因此,显而易见的解决方案就是让后两个模块需要用户模块,而那些需要用户的模块中的任何类都只引用用户 ID。这会破坏规范化,因为它不是外键,所以我不确定这个想法有多好。
我突然想到的另一种可能性是让每个模块的 dbcontext 使用一个接口(interface),并允许使用该模块的人声明他们自己的 dbcontext 并实现所有这些成员,但我不确定这是否可行。
我基本上只是想制作一组类库模块,这些模块定义了一组可供其他程序员使用的通用类和 API 调用,同时使用 EF 作为基础,目的是将它们全部存储在一个数据库中。但我不太确定如何通过 DbContexts 的工作方式来实现这一点。当您有多个模块需要同一个对象时会发生什么?
最佳答案
您所代表的三个上下文通常匹配 Bounded Contexts按照 Domain-driven design 中的设计,正如 Steeve 正确指出的那样。
显然有多种方法可以实现这种情况,每种方法都各有利弊。
我建议采用两种方法来尊重领域驱动设计的最佳实践并具有很大的灵 active 。
方法 #1:软分离
我在第一个限界上下文中定义了一个 User
类,在第二个限界上下文中定义了一个表示对用户的引用的接口(interface)。
让我们定义用户:
class User
{
[Key]
public Guid Id { get; set; }
public string Name { get; set; }
}
其他引用用户的模型实现IUserRelated
:
interface IUserRelated
{
[ForeignKey(nameof(User))]
Guid UserId { get; }
}
设计模式建议不要直接链接来自两个分离的有界上下文的两个实体,而是存储它们各自的引用。
Building
类如下所示:
class Building : IUserRelated
{
[Key]
public Guid Id { get; set; }
public string Location { get; set; }
public Guid UserId { get; set; }
}
如您所见,Building
模型只知道 User
的引用。尽管如此,该接口(interface)充当外键并限制插入到此 UserId
属性中的值。
现在让我们定义数据库上下文...
class BaseContext<TContext> : DbContext where TContext : DbContext
{
static BaseContext()
{
Database.SetInitializer<TContext>(null);
}
protected BaseContext() : base("Demo")
{
}
}
class UserContext : BaseContext<UserContext>
{
public DbSet<User> Users { get; set; }
}
class BuildingContext : BaseContext<BuildingContext>
{
public DbSet<Building> Buildings { get; set; }
}
以及初始化数据库的数据库上下文:
class DatabaseContext : DbContext
{
public DbSet<Building> Buildings { get; set; }
public DbSet<User> Users { get; set; }
public DatabaseContext() : base("Demo")
{
}
}
最后,创建用户和建筑物的代码:
// Defines some constants
const string userName = "James";
var userGuid = Guid.NewGuid();
// Initialize the db
using (var db = new DatabaseContext())
{
db.Database.Initialize(true);
}
// Create a user
using (var userContext = new UserContext())
{
userContext.Users.Add(new User {Name = userName, Id = userGuid});
userContext.SaveChanges();
}
// Create a building linked to a user
using (var buildingContext = new BuildingContext())
{
buildingContext.Buildings.Add(new Building {Id = Guid.NewGuid(), Location = "Switzerland", UserId = userGuid});
buildingContext.SaveChanges();
}
方法 #2:硬分离
我在每个限界上下文中定义了一个 User
类。接口(interface)强制执行公共(public)属性。 Martin Fowler 说明了这种方法,如下所示:
用户限界上下文:
public class User : IUser
{
[Key]
public Guid Id { get; set; }
public string Name { get; set; }
}
public class UserContext : BaseContext<UserContext>
{
public DbSet<User> Users { get; set; }
}
构建限界上下文:
public class User : IUser
{
[Key]
public Guid Id { get; set; }
}
public class Building
{
[Key]
public Guid Id { get; set; }
public string Location { get; set; }
public virtual User User { get; set; }
}
public class BuildingContext : BaseContext<BuildingContext>
{
public DbSet<Building> Buildings { get; set; }
public DbSet<User> Users { get; set; }
}
在这种情况下,在 BuildingContext
中拥有一个 Users
属性是完全可以接受的,因为用户也存在于建筑物的上下文中。
用法:
// Defines some constants
const string userName = "James";
var userGuid = Guid.NewGuid();
// Create a user
using (var userContext = new UserContext())
{
userContext.Users.Add(new User { Name = userName, Id = userGuid });
userContext.SaveChanges();
}
// Create a building linked to a user
using (var buildingContext = new BuildingContext())
{
var userReference = buildingContext.Users.First(user => user.Id == userGuid);
buildingContext.Buildings.Add(new Building { Id = Guid.NewGuid(), Location = "Switzerland", User = userReference });
buildingContext.SaveChanges();
}
使用 EF 迁移非常简单。用户限界上下文的迁移脚本(由 EF 生成):
public partial class Initial : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.Users",
c => new
{
Id = c.Guid(nullable: false),
Name = c.String(),
})
.PrimaryKey(t => t.Id);
}
public override void Down()
{
DropTable("dbo.Users");
}
}
构建限界上下文的迁移脚本(由 EF 生成)。我必须删除表 Users
的创建,因为另一个有界上下文负责创建它。在为模块化方法创建表之前,您仍然可以检查该表是否不存在:
public partial class Initial : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.Buildings",
c => new
{
Id = c.Guid(nullable: false),
Location = c.String(),
User_Id = c.Guid(),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.Users", t => t.User_Id)
.Index(t => t.User_Id);
}
public override void Down()
{
DropForeignKey("dbo.Buildings", "User_Id", "dbo.Users");
DropIndex("dbo.Buildings", new[] { "User_Id" });
DropTable("dbo.Users");
DropTable("dbo.Buildings");
}
}
为这两个上下文应用Upgrade-Database
,您的数据库就准备好了!
编辑关于在 User
类中添加新属性的 OP 请求。
当有界上下文向类 User
添加新属性时,它会在后台逐渐添加一个新列。它不会重新定义整个表。这就是此实现也非常通用的原因。
下面是一个迁移脚本示例,其中一个新属性 Accreditation
添加到限界上下文 Building
中的类 User
:
public partial class Accreditation : DbMigration
{
public override void Up()
{
AddColumn("dbo.Users", "Accreditation", c => c.String());
}
public override void Down()
{
DropColumn("dbo.Users", "Accreditation");
}
}
关于c# - 如何首先在 EF 代码中处理一个数据库在多个数据库上下文中使用的一个类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39456105/
出现以下错误 Network access for Distributed Transaction Manager (MSDTC) has been disabled. Please enable D
在调试应用程序时出现以下错误。 The CLR has been unable to transition from COM context 0x3b2d70 to COM context 0x3b2
在 GAE Go 中,为了记录,我们需要使用 appengine.NewContext(r) 创建一个新的上下文,它返回 context.Context。 如何使用此上下文在请求范围内设置/获取变量?
我想使用 Puppeteer 从放置在页面上 iframe 内的选择器中获取数据,该页面在与其父框架域不同的域上运行。因此,我不是任何域的所有者 - 无法使用 frame.postMessage。 试
我正在尝试获取可用的应用程序上下文并想切换到 webview 上下文,但 appium 仅获取 Navive App。 应用程序还启用了 WebView。 Appium 版本:1.10.1 Chrom
这个问题在这里已经有了答案: How to fix this nullOk error when using the flutter_svg package? (7 个回答) 7 个月前关闭。 当我尝
我观看了关于 Core Data 的 2016 WWDC 视频并查看了各种教程。我见过使用 Core Data Framework 创建对象以持久保存到 managedObjectContext 中的
这是代码 obj = { a: 'some value'; m: function(){ alert(this.a); } } obj.m(); 结果是'som
我正在尝试做类似的事情 $(".className").click(function() { $(this).(".anotherClass").css("z-index","1");
var User = { Name: "Some Name", Age: 26, Show: function() { alert("Age= "+this.Age)}; }; fun
我目前正在使用我见过的常见 Context 模式,它允许子组件通过传递修饰函数来更新父组件的状态(即 Provider)通过共享的 Context。 我遇到的问题是,修改函数只引用原始状态,不引用最新
有没有办法让 React Context类型安全与流类型? 例如: Button.contextTypes = { color: React.PropTypes.string }; 最佳答案 不幸
我想知道是否有一种方法可以为不同的功能使用不同的上下文类。 我希望有一个功能使用 MinkExtensions 进行浏览器测试,另一个功能使用和 HTTP 客户端(如 Guzzle)进行 API 测试
我有这个配置文件 apiVersion: v1 clusters: - cluster: server: [REDACTED] // IP of my cluster name: stag
我在实现非抢先式调度时遇到了用于初始化TCB的代码。 typedef struct TCB_t { struct TCB_t *next; struct TCB_t
我想将一个函数设置为数组中每个元素的属性,但使用不同的参数调用它。我想我会使用匿名函数来解决它: for ( var i = 0; i < object_count; i++ ) { obje
这个问题已经有答案了: How to access the correct `this` inside a callback (15 个回答) 已关闭 7 年前。 我正在做一些练习,但我在管道方法中丢
我正在尝试通过 Java 和 Android Studio 学习和制作 Android 应用程序。我对Java的了解程度是两年前几个小时的youtube学习和大学基础类(class)。不过我确实知道如
我在(这个)上遇到了问题。错误ImageView无法应用。我在 fragment 类中执行此代码。 ViewFlipper v_flipper; @Nullable @Override public
我想使用 openGL 的某些功能,但与渲染视觉内容无关。有没有办法在没有任何依赖性的情况下创建它(不是对 Windows,也不是某些包[SDL,SFML,GLUT])?只允许使用没有外部库的库,就像
我是一名优秀的程序员,十分优秀!