EF一对一可选关系导航属性不起作用

时间:2016-08-19 04:14:56

标签: c# entity-framework ef-code-first

我有PaymentsReviews

public class Payment {

        [Key]
        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public int PaymentId { get; set; }

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

        // other properties
}

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

        [ForeignKey("PeerPayment")]
        public int? PeerPaymentId { get; set; }
        public virtual PeerPayment PeerPayment { get; set; }
}

我将它们映射如下:

    public ReviewConfiguration() {
        // One-to-One optional:optional
        HasOptional(s => s.Payment).WithMany().HasForeignKey(x => x.PaymentId);
    }

    public PaymentConfiguration() {
        // One-to-One optional:optional
        HasOptional(s => s.Review).WithMany().HasForeignKey(s => s.ReviewId);
    }

我的数据库FK创建为nullable,非常棒。但是,以下测试失败:

    public async Task ReviewPeerPaymentWorks() {
        using (var db = new AppContext()) {
            var user1 = db.FindUser("M1");
            var user2 = db.FindUser("M2");
            var review = new Review() {
                FromUserId = user1.UserId,
                ToUserId = user2.UserId
            };
            db.Reviews.Add(review);
            var payment = new Payment() {
                FromUserId = user1.UserId,
                ToUserId = user2.UserId,
                ReviewId = review.ReviewId
            };
            db.Payments.Add(payment);
            db.SaveChanges();

            review = db.Reviews.First(s => s.ReviewId == review.ReviewId);
            payment = db.Payments.First(s => s.PaymentId == payment.PaymentId);
            Assert.AreEqual(review.PaymentId, payment.PaymentId); // fails - review.PaymentId is always null
            Assert.AreEqual(review.ReviewId, payment.ReviewId); // passes
            Assert.AreEqual(review.Payment.PaymentId, payment.Review.PaymentId); // fails - review.Payment is null, payment.Review.PaymentId is null
        }
    }

我做错了什么?

要明确 - 我不想修改我的测试,除非有人认为这是因为某种原因测试关系的无效方法。

3 个答案:

答案 0 :(得分:1)

EF中的一对一关系有点棘手。特别是在Code-First中。 在DB-First中,我会对两个FK属性进行UNIQUE约束,以确保每个表只出现一次这种关系(但请确​​保它不是一对一或零,因为UNIQUE约束将允许您只有一个NULL FK值)。在NULLable FK的情况下,它可以通过第三个关系表完成,对关系表中的所有列都有UNIQUE约束。

以下是解释EF如何映射一对一关系的网址:http://www.entityframeworktutorial.net/entity-relationships.aspx
以下是解释如何配置一对一关系的网址:http://www.entityframeworktutorial.net/code-first/configure-one-to-one-relationship-in-code-first.aspx

通常他们建议对两个表使用相同的PK值:

  

"因此,我们需要以EF创建的方式配置上述实体   学生和学生地址表将在DB中进行   学生表中的StudentId为PK, StudentAddressId列为   StudentAddress表为PK和FK 。"

我试过你的例子,你在评论和付款之间做了两个独立的一对多关系。但没有许多导航属性。 看 WithMany()

.HasOptional(s => s.Review).WithMany().HasForeignKey(s => s.ReviewId); 

这是真正的一对多关系,没有MANY(列表)导航属性。查看MSSQL图:

MSSQL diagram

之所以你得到NULL值 - 因为你已经分配了Payment.ReviewId关系并且没有分配Review.PaymentId关系。但是你预计EF会自动完成它。由于它们是单独的关系 - EF因为你没有指定它而留下其中一个

答案 1 :(得分:0)

public async Task ReviewPeerPaymentWorks() {
    using (var db = new AppContext()) {
        var user1 = db.FindUser("M1");
        var user2 = db.FindUser("M2");
        var review = new Review() {
            FromUserId = user1.UserId,
            ToUserId = user2.UserId
        };
        db.Reviews.Add(review);
        var payment = new Payment() {
            FromUserId = user1.UserId,
            ToUserId = user2.UserId,
            ReviewId = review.ReviewId
        };

        db.Payments.Add(payment);
        db.SaveChanges();
        review.Payment = payment;
        db.SaveChanges();


        review = db.Reviews.First(s => s.ReviewId == review.ReviewId);
        payment = db.Payments.First(s => s.PaymentId == payment.PaymentId);
        Assert.AreEqual(review.PaymentId, payment.PaymentId); // fails - review.PaymentId is always null
        Assert.AreEqual(review.ReviewId, payment.ReviewId); // passes
        Assert.AreEqual(review.Payment.PaymentId, payment.Review.PaymentId); // fails - review.Payment is null, payment.Review.PaymentId is null
    }
}

答案 2 :(得分:-1)

我曾两次面对这个问题。每次我从Edmx中删除这两个实体并重新添加。它解决了我的问题。

希望它能与你合作