是否可以设置没有外键的导航属性?

时间:2019-07-11 22:47:59

标签: c# .net entity-framework .net-core entity-framework-core

是否可以具有两个(或多个)相同类型的导航属性?

我的模特看起来像这样...

public class Agreement
{
    public int Id { get; set; }
    public Guid? BuyerId { get; set; }
    public Guid? SellerId { get; set; }

    public AgreementInfo ByerAgreementInfo { get; set; }
    public AgreementInfo SellerAgreementInfo { get; set; }
}

public class AgreementInfo
{
    // PK is AgreementId and OwnerActorId combined.
    public int AgreementId { get; set; }
    public Guid OwnerActorId { get; set; }
    public string Name { get; set; }
}

...并且我正在尝试通过匹配AgreementId和ByerId / SellerId ...来包括导航属性...

modelBuilder.Entity<Agreement>().HasOne(x => x.ByerAgreementInfo).WithOne().HasForeignKey<Agreement>(x => new {x.Id, x.ProviderId});
modelBuilder.Entity<Agreement>().HasOne(x => x.SellerAgreementInfo).WithOne().HasForeignKey<Agreement>(x => new { x.Id, x.RequesterId });
  

...但是这导致了循环依赖。

有没有不用外键就可以包含这些属性的方法?还是有另一种解决方案(除了在信息表中添加ID列之外),允许我将信息表行用作协议类中的导航属性?

2 个答案:

答案 0 :(得分:0)

有多种方法可以实现您想要的。您可以将数据注释与孩子的InverseProperty属性,父母的ForeignKey属性或流利的语法一起用于模型构建器。我倾向于在我可以使用的属性(数据注释)中(只是我的个人喜好),我发现它需要查看实际模式本身中的关系(尽管其他人可能没有)。

使用ForeignKey属性

public class Agreement
{
    ...

    [ForeignKey("ByerAgreementInfo ")]
    public int ByerAgreementInfoId { get; set; }
    public AgreementInfo ByerAgreementInfo { get; set; }

    [ForeignKey("SellerAgreementInfo ")]
    public int SellerAgreementInfoId { get; set; }
    public AgreementInfo SellerAgreementInfo { get; set; 
}

使用InverseProperty属性

public class AgreementInfo
{

    ...

    [InverseProperty("ByerAgreementInfo ")]
    public ICollection<Agreement> Sellers { get; set; }
    [InverseProperty("SellerAgreementInfo ")]
    public ICollection<Agreement> Buyers { get; set; }
}

如果您想使用 Fluent语法,我相信以下内容会起作用(尽管我已经有一段时间没有使用它了)

modelBuilder.Entity<Agreement>()
    .HasOne(x => x.ByerAgreementInfo)
    .WithOne()
    .HasForeignKey<Agreement>(p => p.ByerAgreementInfoId);

modelBuilder.Entity<Agreement>()
    .HasOne(x => x.SellerAgreementInfo)
    .WithOne()
    .HasForeignKey<Agreement>(p => p.SellerAgreementInfoId);

注意 :我认为您可能需要模型中的实际ID,尽管我不记得了

答案 1 :(得分:0)

  

...但是这导致了循环依赖

是的!它会。为了克服这个问题,您必须在 Fluent API 配置中指定.OnDelete(DeleteBehavior.Restrict);,如下所示,但首先您也必须编写Agreement模型类,如下所示:

public class Agreement
{
    public int Id { get; set; }
    public Guid? BuyerId { get; set; }
    public Guid? SellerId { get; set; }

    public int AgreementIdForBuyer { get; set; }
    public Guid OwnerActorIdForBuyer { get; set; }

    public int AgreementIdForSeller { get; set; }
    public Guid OwnerActorIdForSeller { get; set; }

    public AgreementInfo ByerAgreementInfo { get; set; }
    public AgreementInfo SellerAgreementInfo { get; set; }
}

现在处于 Fluent API 配置中:

modelBuilder.Entity<Agreement>()
    .HasOne(x => x.ByerAgreementInfo)
    .WithOne()
    .HasForeignKey<Agreement>(p => new {p.AgreementIdForBuyer, p.AgreementIdForBuyer})
    .OnDelete(DeleteBehavior.Restrict); // <-- Here it is

modelBuilder.Entity<Agreement>()
    .HasOne(x => x.SellerAgreementInfo)
    .WithOne()
    .HasForeignKey<Agreement>(p => new {p.AgreementIdForSeller, p.OwnerActorIdForSeller})
    .OnDelete(DeleteBehavior.Restrict); // <-- Here it is