简体   繁体   English

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

[英]EF One-to-one optional relationship navigation properties not working

I have Payments and Reviews . 我有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; }
}

I've mapped them as follows: 我将它们映射如下:

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

My database FKs are created as nullable , which is great. 我的数据库FK创建为nullable ,这很棒。 However the following test fails: 但是,以下测试失败:

    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
        }
    }

What am I doing wrong? 我究竟做错了什么?

To be clear - I don't want to modify my test, unless someone thinks it's an invalid way to test the relationship for some reason. 明确地说-我不想修改测试,除非有人出于某种原因认为这是测试关系的无效方法。

One-to-One relation is a bit tricky in the EF. 在EF中,一对一关系有些棘手。 Especially in Code-First. 特别是在代码优先中。 In the DB-First I would make the UNIQUE constraint on the both FK properties to make sure that this relation appear only once per table (but please make sure that it's not One-to-One-or-Zero because UNIQUE constraint will allow you to have only one NULL FK value). 在DB-First中,我将对两个FK属性都设置UNIQUE约束,以确保该关系在每个表中仅出现一次(但请确保它不是一对一或零的,因为UNIQUE约束将允许您只能有一个NULL FK值)。 In case of the NULLable FK it can be done via the 3rd relation table with the UNIQUE constraint over all columns in relation table. 如果为NULLable FK,则可以通过第3个关系表,对关系表中的所有列进行UNIQUE约束。

Here is the URL which explains how EF maps the One-to-One relationship: http://www.entityframeworktutorial.net/entity-relationships.aspx 以下是解释EF如何映射一对一关系的URL: http : //www.entityframeworktutorial.net/entity-relationships.aspx
Here is the URL which explains how to configure One-to-One relationship: http://www.entityframeworktutorial.net/code-first/configure-one-to-one-relationship-in-code-first.aspx 这是解释如何配置一对一关系的URL: http : //www.entityframeworktutorial.net/code-first/configure-one-to-one-relationship-in-code-first.aspx

Generally they suggest to use the same PK values for both tables: 通常,他们建议对两个表使用相同的PK值:

"So, we need to configure above entities in such a way that EF creates Students and StudentAddresses table in the DB where it will make StudentId in Student table as PK and StudentAddressId column in StudentAddress table as PK and FK both ." “因此,我们需要以一种这样的方式配置上述实体,即EF在数据库中创建Student和StudentAddresses表,它将在Student表中将StudentId设置为PK, 在StudentAddress表中将StudentAddressId列设置为PK和FK

I have tried your example and you did two independent One-to-Many relations between Review and Payment. 我尝试了您的示例,您在“查看”和“付款”之间建立了两个独立的一对多关系。 But without the Many navigation property. 但是没有多导航属性。 Look WithMany() : WithMany()

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

So it's real One-To-Many relation with no MANY (List) navigation properties. 因此,它是真正的一对多关系,没有MANY(列表)导航属性。 Look at the MSSQL diagram: 看一下MSSQL图:

MSSQL图

And the reason why did you get the NULL values - because you have assigned Payment.ReviewId relation and didn't assign the Review.PaymentId relation. 以及为什么得到NULL值的原因-因为您已分配Payment.ReviewId关系,而未分配Review.PaymentId关系。 But you expected EF did it automatically. 但是您希望EF能够自动执行。 Since they are separate relations - EF left one of the as NULL because you didn't assign it 由于它们是独立的关系-EF保留其中之一为NULL,因为您未分配它

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
    }
}

I have faced this issue two times. 我已经两次面对这个问题。 Each time I have removed those two entities from Edmx and re-added. 每次我从Edmx中删除这两个实体并重新添加时。 It solves my issue. 它解决了我的问题。

Hopefully it will work with you 希望它将与您合作

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM