1

在代码中我有一个对象图,看起来像这样:如何建立具有多种原则的'拥有'数据库关系?

public class Author 
{ 
    public int AuthorId { get; set; } 
    public string Name { get; set; } 
    public Address Address { get; set; } 
} 

public class Publisher 
{ 
    public int PublisherId { get; set; } 
    public string Name { get; set; } 
    public Address Address { get; set; } 
} 

public class Address 
{ 
    public int AddressId { get; set; } 
    public string Postcode { get; set; } 
} 

如何在关系数据库模式的模型呢?

这需要是0-1..1的关系,即作者和发布者可能有或没有地址。

理想情况地址必须由作者或发布者引用,但不能同时引用。

如果您可以使用导航属性在实体框架核心中对其进行建模,并且级联删除删除作者或发布者时删除地址,则可以获得巨大的奖励。 (但我敢打赌,没有人能够)。

我列出了所有我尝试过的东西,但是这个帖子太久没有人会阅读它了。只是说我已经尝试了所有我能想到的事情就会更快。

+0

我们可以添加属性'Address'类或它应该保持它的方式是现在? –

+0

您可以将地址添加到地址。所有表格可根据需要进行调整以建立所需关系。 – Neutrino

回答

4

您有很多方法可以在EF Core中实现目标。关键的一点是,Address将是关系的依赖结束,它将包含可选 FKS到主要实体AuthorPublisher

这里是可能Address型号和配置:

(1)Address具有明确FK和导航属性

型号:

public class Address 
{ 
    public int AddressId { get; set; } 
    public string Postcode { get; set; } 

    public int? AuthorId { get; set; } 
    public Author Author { get; set; } 

    public int? PublisherId { get; set; } 
    public Publisher Publisher { get; set; } 
} 

配置:

modelBuilder.Entity<Author>() 
    .HasOne(e => e.Address) 
    .WithOne(e => e.Author) 
    .HasForeignKey<Address>(e => e.AuthorId) 
    .OnDelete(DeleteBehavior.Cascade); 

modelBuilder.Entity<Publisher>() 
    .HasOne(e => e.Address) 
    .WithOne(e => e.Publisher) 
    .HasForeignKey<Address>(e => e.PublisherId) 
    .OnDelete(DeleteBehavior.Cascade); 

(2)与Address导航属性仅

型号:

public class Address 
{ 
    public int AddressId { get; set; } 
    public string Postcode { get; set; } 

    public Author Author { get; set; } 

    public Publisher Publisher { get; set; } 
} 

配置:

modelBuilder.Entity<Author>() 
    .HasOne(e => e.Address) 
    .WithOne(e => e.Author) 
    .HasForeignKey<Address>("AuthorId") 
    .OnDelete(DeleteBehavior.Cascade); 

modelBuilder.Entity<Publisher>() 
    .HasOne(e => e.Address) 
    .WithOne(e => e.Publisher) 
    .HasForeignKey<Address>("PublisherId") 
    .OnDelete(DeleteBehavior.Cascade); 

(3)Address具有明确FK属性仅

型号:

public class Address 
{ 
    public int AddressId { get; set; } 
    public string Postcode { get; set; } 

    public int? AuthorId { get; set; } 

    public int? PublisherId { get; set; } 
} 

配置:

modelBuilder.Entity<Author>() 
    .HasOne(e => e.Address) 
    .WithOne() 
    .HasForeignKey<Address>(e => e.AuthorId) 
    .OnDelete(DeleteBehavior.Cascade); 

modelBuilder.Entity<Publisher>() 
    .HasOne(e => e.Address) 
    .WithOne() 
    .HasForeignKey<Address>(e => e.PublisherId) 
    .OnDelete(DeleteBehavior.Cascade); 

(4)Address没有明确FK和导航属性

型号:

public class Address 
{ 
    public int AddressId { get; set; } 
    public string Postcode { get; set; } 
} 

配置:

modelBuilder.Entity<Author>() 
    .HasOne(e => e.Address) 
    .WithOne() 
    .HasForeignKey<Address>("AuthorId") 
    .OnDelete(DeleteBehavior.Cascade); 

modelBuilder.Entity<Publisher>() 
    .HasOne(e => e.Address) 
    .WithOne() 
    .HasForeignKey<Address>("PublisherId") 
    .OnDelete(DeleteBehavior.Cascade); 

参考:Relationships

+0

我认为拥有类型将是一个选项,不是吗? (“所有表格可根据需要进行调整以建立所需关系”)。 –

+0

@Gert当然。但是按照我的理解,OP明确希望1到0..1的关系(*作者和发布者可能有或没有地址*),而拥有类型代表1到1(即必需)关系,如EF6复杂类型? –

+1

是的,这是复杂类型的ef-core等价物。但当然这不是可选的,所以我想它并不完全符合法案。尽管对于OP来说可能值得考虑,因为它极大地简化了数据模型,地址字段是所有者表的一部分。缺点:如果你想创建*一个*,你总是必须创建*两个*实体('Publisher'和'Address'等)。但是一个小小的工厂方法会掩盖这种不便。我认为我会为此付出代价(但我对少数多态关联和可空的外键过敏)。 –