一对一可选关系,两端可选,两个FK

Rob*_*ous 2 .net entity-framework ef-code-first entity-framework-6

我正在关注这个问题:EF Code First - 1对1可选关系

我的关系设置如下:

public class Review {
    [Key]
    public int ReviewId { get; set; }

    public virtual Payment Payment { get; set; }
}

public class Payment {
    [Key]
    public int PaymentId { get; set; }

    [ForeignKey("Review")]
    public int? ReviewId { get; set; }
    public virtual Review Review { get; set; }
}

    public class ReviewConfiguration : EntityTypeConfiguration<Review>
{
    public ReviewConfiguration()
    {
        // One-to-One Optional
        HasOptional<Payment>(s => s.Payment).WithOptionalDependent(s => s.Review).Map(s => s.MapKey("PaymentId"));
    }
}
Run Code Online (Sandbox Code Playgroud)

我得到一个有效的密钥,但另一个从未映射为可选的FK:

在此输入图像描述

我究竟做错了什么?

我已经看到一些奇怪的hacky解决方案涉及创建空列表等 - 而不是我正在寻找的.我在这里寻找一个合适的方法 - 它必须存在......对吗?

更新

我现在正在使用上面的内容 - 当我手头有付款并且需要访问或删除评论时,我必须在[伪FK] ReviewId上进行另一次查找,这完全很糟糕.

Ger*_*old 7

在任何一对一关联中,EF仅使用一个外键.当需要的关联,外键也将取决于实体的主键,如解释在这里.

当关联是可选的时,两个实体应该能够彼此独立地存在.所以他们的主键不能是外键,因为PK不能是可选的.这里需要一个额外的可空FK字段来建立可选的关联.

在您的情况下,从技术上讲,哪个实体具有FK字段(逻辑上,它可能)并不重要.我用过这个模型:

public class Review
{
    [Key]
    public int ReviewId { get; set; }
    public virtual Payment Payment { get; set; }
}

public class Payment
{
    [Key]
    public int PaymentId { get; set; }

    public Review Review { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

有了这个映射:

public class ReviewConfiguration : EntityTypeConfiguration<Review>
{
    public ReviewConfiguration()
    {
        // One-to-One Optional
        HasOptional(s => s.Payment)
            .WithOptionalDependent(s => s.Review)
            .Map(s => s.MapKey("PaymentId"));
    }
}
Run Code Online (Sandbox Code Playgroud)

(所以,除此之外Payment.ReviewId,这与你问题中的模型+映射相同).

现在我可以做......

db.Set<Review>().Add(new Review { Payment = new Payment() });
db.Set<Payment>().Add(new Payment { Review = new Review() });
db.SaveChanges();
Run Code Online (Sandbox Code Playgroud)

...... db当然是一个背景.这两个表的内容现在是:

PaymentId
-----------
1
2

ReviewId    PaymentId
----------- -----------
1           1
2           2
Run Code Online (Sandbox Code Playgroud)

我可以像这样双向查询数据:

var data = db.Set<Review>().Include(r => r.Payment).ToList();
Run Code Online (Sandbox Code Playgroud)

要么

var data = db.Set<Payment>().Include(r => r.Review).ToList();
Run Code Online (Sandbox Code Playgroud)

但是ReviewConfiguration,我也可以使用......

public class PaymentConfiguration : EntityTypeConfiguration<Payment>
{
    public PaymentConfiguration()
    {
        // One-to-One Optional
        HasOptional(s => s.Review)
            .WithOptionalDependent(s => s.Payment)
            .Map(s => s.MapKey("ReviewId"));
    }
}
Run Code Online (Sandbox Code Playgroud)

现在ReviewId表中将有一个FK字段,Payment其余代码无需更改即可运行.