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

时间:2016-05-05 01:09:53

标签: .net entity-framework ef-code-first entity-framework-6

我关注这个问题:EF Code First - 1-to-1 Optional Relationship

我的关系设置如下:

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"));
    }
}

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

enter image description here

我做错了什么?

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

更新

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

2 个答案:

答案 0 :(得分:7)

在任何一对一关联中,EF仅使用一个外键。当需要关联时,外键也将是依赖实体的主键,如here所述。

当关联是可选的时,两个实体应该能够彼此独立地存在。所以他们的主键不能是外键,因为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; }
}

使用此映射:

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

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

现在我可以做点像......

db.Set<Review>().Add(new Review { Payment = new Payment() });
db.Set<Payment>().Add(new Payment { Review = new Review() });
db.SaveChanges();

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

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

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

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

var data = db.Set<Review>().Include(r => r.Payment).ToList();

var data = db.Set<Payment>().Include(r => r.Review).ToList();

但我可以使用...... {/ p>而不是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"));
    }
}

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

答案 1 :(得分:1)

您的模型中必须存在拼写错误(付款中有2个ReviewId字段?)。此外,如果你走的是流畅的路线,不要在那里放置任何关系属性来混淆事情。 IAC,尝试这样的事情:

public class Review {
    public int ReviewId { get; set; }

    public int? PaymentId { get; set; }
    public virtual Payment Payment { get; set; }
}

public class Payment {
    public int PaymentId { get; set; }

    public int? ReviewId { get; set; }
    public virtual Review Review { get; set; }
}

public class ReviewConfiguration : EntityTypeConfiguration<Review>
{
    public ReviewConfiguration()
    {
        HasOptional(r => r.Payment)
            .WithMany()
            .HasForeignKey(r => r.PaymentId);
    }
}

public class PaymentConfiguration : EntityTypeConfiguration<Payment>
{
    public PaymentConfiguration()
    {
        HasOptional(p => p.Review)
            .WithMany()
            .HasForeignKey(p => p.ReviewId);
    }
}