首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >使用实体框架实现实体间的复杂关系

使用实体框架实现实体间的复杂关系
EN

Stack Overflow用户
提问于 2019-06-26 22:23:12
回答 2查看 280关注 0票数 3

也许这是一个复制品,但我找不到任何这样的主题。

我使用的是Entity Framework,数据库中有两个表:

代码语言:javascript
复制
public class A
{
    public virtual B B1 { get; set; }
    public virtual B B2 { get; set; }
}

public class B
{
    public virtual A A1 { get; set; }
}

B1与A1、B2与A1无相关性。它就像3个单向的关系。如何在Entity Framework中做到这一点?

我得到了这个错误:

保存不公开其关系的外键属性的实体时出错

有人知道怎么处理这件事吗?

提前感谢

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-06-29 05:18:42

由于您没有指明您使用的是哪个EF版本,让我们来看看当前的两个版本,EF 6.2.0和EF-core 2.2.4。

使用EF6,这很容易。映射..。

代码语言:javascript
复制
modelBuilder.Entity<A>().HasRequired(a => a.B1).WithMany();
modelBuilder.Entity<A>().HasRequired(a => a.B2).WithMany().WillCascadeOnDelete(false);
modelBuilder.Entity<B>().HasRequired(b => b.A1).WithMany().WillCascadeOnDelete(false);

...produces以下数据库模型(忽略索引):

代码语言:javascript
复制
CREATE TABLE [dbo].[A] (
    [ID] [int] NOT NULL IDENTITY,
    [B1_ID] [int] NOT NULL,
    [B2_ID] [int] NOT NULL,
    CONSTRAINT [PK_dbo.A] PRIMARY KEY ([ID])
)
CREATE TABLE [dbo].[B] (
    [ID] [int] NOT NULL IDENTITY,
    [A1_ID] [int] NOT NULL,
    CONSTRAINT [PK_dbo.B] PRIMARY KEY ([ID])
)

_的字段为外键的....in,其中一个可以级联delete。

有了ef-core,看起来就不那么简单了,甚至出现了buggy。第一个脉冲是EF6的等价物:

代码语言:javascript
复制
modelBuilder.Entity<A>().HasOne(a => a.B1).WithMany();
modelBuilder.Entity<A>().HasOne(a => a.B2).WithMany();
modelBuilder.Entity<B>().HasOne(b => b.A1).WithMany();

但是生成的模型并不是人们所期望的:

代码语言:javascript
复制
  CREATE TABLE [B] (
      [ID] int NOT NULL IDENTITY,
      [A1ID] int NULL,
      CONSTRAINT [PK_B] PRIMARY KEY ([ID])
  );
  CREATE TABLE [A] (
      [ID] int NOT NULL,
      [B1ID] int NULL,
      CONSTRAINT [PK_A] PRIMARY KEY ([ID]),
      CONSTRAINT [FK_A_B_B1ID] FOREIGN KEY ([B1ID]) REFERENCES [B] ([ID]) ON DELETE NO ACTION,
      CONSTRAINT [FK_A_B_ID] FOREIGN KEY ([ID]) REFERENCES [B] ([ID]) ON DELETE CASCADE
  );
  ALTER TABLE [B] ADD CONSTRAINT [FK_B_A_A1ID] FOREIGN KEY ([A1ID]) REFERENCES [A] ([ID]) ON DELETE NO ACTION;

其中一个A-B关联被解释为1:1。在我看来,这是一个错误。WithMany指令不应该留下任何解释的空间。两个看似相同的映射会产生完全不同的数据库关系。这是不对的。

也就是说,通过命名FK列很容易(但不是必须的)让EF走上正确的轨道:

代码语言:javascript
复制
modelBuilder.Entity<A>().HasOne(a => a.B1).WithMany().HasForeignKey("B1_ID")
    .IsRequired();
modelBuilder.Entity<A>().HasOne(a => a.B2).WithMany().HasForeignKey("B2_ID")
    .IsRequired().OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<B>().HasOne(b => b.A1).WithMany().HasForeignKey("A1_ID")
    .IsRequired().OnDelete(DeleteBehavior.Restrict);

生成(忽略索引):

代码语言:javascript
复制
  CREATE TABLE [B] (
      [ID] int NOT NULL IDENTITY,
      [A1_ID] int NOT NULL,
      CONSTRAINT [PK_B] PRIMARY KEY ([ID])
  );
  CREATE TABLE [A] (
      [ID] int NOT NULL IDENTITY,
      [B1_ID] int NOT NULL,
      [B2_ID] int NOT NULL,
      CONSTRAINT [PK_A] PRIMARY KEY ([ID]),
      CONSTRAINT [FK_A_B_B1_ID] FOREIGN KEY ([B1_ID]) REFERENCES [B] ([ID]) ON DELETE CASCADE,
      CONSTRAINT [FK_A_B_B2_ID] FOREIGN KEY ([B2_ID]) REFERENCES [B] ([ID]) ON DELETE NO ACTION
  );
  ALTER TABLE [B] ADD CONSTRAINT [FK_B_A_A1_ID] FOREIGN KEY ([A1_ID]) REFERENCES [A] ([ID]) ON DELETE NO ACTION;

请注意,必须显式设置外键字段(如果是)。好吧,这只是一个实现细节。

票数 1
EN

Stack Overflow用户

发布于 2019-06-27 07:46:03

如果A1表包含指向同一个B表的B1_Id和B2_Id,但您希望B记录只与A关联一次,那么就我所知的映射过程而言,这是不可能的。没有什么可以阻止您将相同的B记录与B1或B2关联到不同的A记录,那么如何合法地解析B的A引用呢?实体反映数据状态,因此如果它在数据模式中是合法的/非法的,那么对于实体也是一样的。在A上有B it可以形成多对1,或者可以形成1对1,但是要在A上共享2倍FK到B,您需要DB支持B的备用FK,但它不支持。

您可以让A在B中保存两个记录的it,但B不能将单个引用映射回A,它必须伪造它。

代码语言:javascript
复制
public class A
{
   public int AId { get; set; }

   public virtual B B1 { get; set; }
   public virtual B B2 { get; set; }
}

public class B
{
   public int BId { get; set; }

   public virtual ICollection<A> RawA1 { get; private set; } = new List<A>();
   public virtual ICollection<A> RawA2 { get; private set; } = new List<A>();

   [NotMapped]
   public A A
   {
      get { return RawA1.SingleOrDefault() ?? RawA2.SingleOrDefault(); }
   }
}

需要注意的是,你不能在进入EF的任何Linq表达式中使用B.A,因为就EF而言,它并不知道该属性。

另一种方法是在AId驻留在B上的情况下使用一对多,然后在A端限制对集合的允许操作。这里的问题是,除非可以由B记录上的属性明确确定,否则B1 & B2顺序是不可靠的。可以从集合中公开B1和B2未映射的属性,但必须确定考虑这两个元素中的哪一个,或者只是公开集合。最终,您的业务逻辑必须控制A应该只有2个B引用的事实,因为数据库不能强制执行这一点,也不能控制B可以返回到A的2对1关系。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56775079

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档