Skip to main content
 首页 » 编程设计

c#之如何为其中一个是事件项目的项目集合建模

2024年02月25日43insus

我遇到这样一种情况,一个实体有一个不活动的子项列表。此外,他们还有另一个相同类型的“当前/事件”子实体。

以下是理想的建模,但我不知道如何使用 Entity Framework Core:

public class Customer  
{ 
    public Application CurrentApplication { get; set; } 
    public List<Application> PastApplications { get; set; } 
} 
 
public class Application 
{ 
    public bool IsCurrent { get; set; } 
    public Customer Customer { get; set; } 
} 

过去,我通常将其建模为:

public class Customer 
{ 
    public Application CurrentApplication => AllApplications.Single(a => a.IsCurrent); 
    public List<Application> PastApplications => AllApplications.Where(a => !a.IsCurrent);   
    public List<Application> AllApplications { get; set; }    
} 
 
public class Application 
{ 
    public bool IsCurrent { get; set; } 
    public Customer Customer { get; set; } 
} 

但是,我觉得这可能会导致另一个Application被错误地设置为IsCurrent,从而破坏了.Single().

从 DDD 的角度来看,建议的实现方法是什么?如果这与 EF Core 的功能不相符,什么是好的实用建议?

请您参考如下方法:

我不认为这是 DDD 问题,而是如何设计关系数据库模型以及如何使用 EF Core 的问题。

首先您需要确定客户和应用程序之间的关系:

  • 一对多,即一个客户可能有零个或多个应用程序,但一个应用程序只属于一个客户。这种场景也称为主从关系。 Many 端的实体(在本例中为应用程序)存储对其所有者(客户)的引用(称为外键)。
  • 多对多,即一个客户可能有零个或多个应用程序,但一个应用程序也可能属于零个或多个客户。此场景使用额外的“连接”表(通常命名为 CustomerApplication)建模,因此问题最终解决为两个 One-to-May 关系。

如果在给定时间(每个客户)只有一个事件应用程序,则可以使用客户和应用程序之间的一对一(准确地说是零对一)关系对事件应用程序建模(与客户方的外键)。它也可以在您尝试时使用 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?当前应用程序 ID。我们需要为我们的零对多关系明确定义外键(稍后会详细介绍)。可为空的 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 如何将实体映射到数据库表。

基于映射,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(); 
} 

我建议你通读要找到的acticles here熟悉 EF Core。

关于关系数据库建模 this site似乎是有用的资源。