我不认为这是一个 DDD 问题,而是一个如何设计关系数据库模型以及如何使用 EF Core 的问题。
首先您需要确定客户和应用程序之间的关系:
- 一对多,即一个客户可能有零个或多个应用程序,但一个应用程序只属于一个客户。这种场景也称为主从关系。多方实体(本例中为应用程序)存储对其所有者(客户)的引用(称为外键)。
- 多对多,即一个客户可能有零个或多个应用程序,但一个应用程序也可能属于零个或多个客户。此场景使用额外的“连接”表(通常命名为 CustomerApplication)建模,因此问题最终解决为两个一对一关系。
如果在给定时间(每个客户)只有一个活动应用程序,则可以使用客户和应用程序(与客户方的外键)。也可以在您尝试使用 Application 上的标志字段对其进行建模,但这不像外键那样防错(但可能具有更好的性能)。
您发布的代码类似于一对多场景,因此我展示了一个示例。了解以下内容,您可以根据需要轻松将其更改为多对多。
首先让我们定义实体:
public class Customer
{
public int Id { get; set; }
public int? CurrentApplicationId { get; set; }
public Application CurrentApplication { get; set; }
public ICollection<Application> Applications { get; set; }
}
public class Application
{
public int Id { get; set; }
public Customer Customer { get; set; }
}
唯一有趣的部分是int? CurrentApplicationId。我们需要为我们的零对多关系明确定义外键(稍后会详细介绍)。可为空的 int (int?) 告诉 EF 该字段可以为 NULL。
EF 通常能够找出关系映射,但在这种情况下,我们需要明确地向它解释它们:
class DataContext : DbContext
{
// ctor omitted for brevity
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Customer>(customer =>
{
customer.HasMany(entity => entity.Applications)
.WithOne(relatedEntity => relatedEntity.Customer)
.OnDelete(DeleteBehavior.Cascade);
customer.HasOne(entity => entity.CurrentApplication)
.WithOne()
.HasForeignKey<Customer>(entity => entity.CurrentApplicationId);
});
}
public DbSet<Application> Applications { get; set; }
public DbSet<Customer> Customers { get; set; }
}
OnModelCreating 方法中发生的事情称为fluent API configuration。本主题和conventions 是理解和控制 EF 如何将实体映射到 DB 表的必备内容。
基于映射,EF 能够生成(参见code-first migrations)以下数据库架构:
CREATE TABLE [Customers] (
[Id] INTEGER NOT NULL
, [CurrentApplicationId] bigint NULL
, CONSTRAINT [sqlite_master_PK_Customers] PRIMARY KEY ([Id])
, FOREIGN KEY ([CurrentApplicationId]) REFERENCES [Applications] ([Id]) ON DELETE RESTRICT ON UPDATE NO ACTION
);
CREATE UNIQUE INDEX [IX_Customers_CurrentApplicationId] ON [Customers] ([CurrentApplicationId] ASC);
CREATE TABLE [Applications] (
[Id] INTEGER NOT NULL
, [CustomerId] bigint NULL
, CONSTRAINT [sqlite_master_PK_Applications] PRIMARY KEY ([Id])
, FOREIGN KEY ([CustomerId]) REFERENCES [Customers] ([Id]) ON DELETE CASCADE ON UPDATE NO ACTION
);
CREATE INDEX [IX_Applications_CustomerId] ON [Applications] ([CustomerId] ASC);
正是我们想要的。
现在,您如何查询此配置中的活动和非活动应用程序?像这样的:
var customerId = 1;
using (var ctx = new DataContext())
{
var currentApplication = (
from customer in ctx.Customers
where customer.Id == customerId
select customer.CurrentApplication
).FirstOrDefault();
var pastApplications =
(
from customer in ctx.Customers
from application in customer.Applications
where customer.Id == customerId && customer.CurrentApplication != application
select application
).ToArray();
}
我建议您通读 here 的文章以熟悉 EF Core。
至于关系数据库建模this site 似乎是一个有用的资源。