我有Payments
和Reviews
。
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
}
}
我做错了什么?
要明确 - 我不想修改我的测试,除非有人认为这是因为某种原因测试关系的无效方法。
答案 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图:
之所以你得到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中删除这两个实体并重新添加。它解决了我的问题。
希望它能与你合作