Entity Framework 同一个表的两个复合外键,backref 关系不起作用
Entity Framework two composite foreign key to same table, backref relation not working
我有两个类
public class AuctionModel
{
[Key]
public int Id { get; set; }
public virtual UserModel Seller { get; set; }
public string SellerUsername { get; set; }
public string SellerSiteName { get; set; }
public string CurrentWinnerUsername { get; set; }
public string CurrentWinnerSiteName { get; set; }
public virtual UserModel CurrentWinner { get; set; }
}
和
public class UserModel : Base
{
[Key]
[Column(Order = 2)]
public string Username { get; set; }
[Key]
[Column(Order = 1)]
public string SiteName { get; set; }
public virtual SiteModel Site { get; set; }
public List<AuctionModel> Auctions { get; set; }
public List<AuctionModel> WinningAuctions { get; set; }
}
而 Fluent Api 将关系指定为
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Entity<AuctionModel>()
.HasRequired(a => a.Seller)
.WithMany(u => u.Auctions)
.HasForeignKey(a => new {a.SellerUsername, a.SellerSiteName});
modelBuilder.Entity<AuctionModel>()
.HasOptional(a => a.CurrentWinner)
.WithMany(u => u.WinningAuctions)
.HasForeignKey(a => new {a.CurrentWinnerSiteName, a.CurrentWinnerUsername});
}
据我所知,这应该可以正常工作,但实际情况是 UserModel.Auctions 和 CurrentModel.WinningAuctions 始终为空。我知道对象已附加,因为我检查过并且即使在我将对象保存到数据库后关系也为空。
更新:
return context.Users.Include("MyAuctions").Include("WinningAuctions").First(u => u.Username == userName && u.SiteName == siteName);
使用 Includes 加载数据,加载关系。这在某种程度上是可以预料的,但即使我将关系更改为
public virtual List<AuctionModel> MyAuctions { get; set; }
public virtual List<AuctionModel> WinningAuctions { get; set; }
我仍然必须使用 Include,否则我会得到 null。这对我来说真的没有意义。
所以我不完全确定如何使用 Fluent API 解决此问题,但以下是使用数据注释的方法:
public class AuctionModel
{
[Key]
public int Id { get; set; }
[Required, ForeignKey("Seller"), Column(Order = 2)]
public string SellerUsername { get; set; }
[Required, ForeignKey("Seller"), Column(Order = 3)]
public string SellerSiteName { get; set; }
[ForeignKey("CurrentWinner"), Column(Order = 4)]
public string CurrentWinnerUsername { get; set; }
[ForeignKey("CurrentWinner"), Column(Order = 5)]
public string CurrentWinnerSiteName { get; set; }
public virtual UserModel Seller { get; set; }
public virtual UserModel CurrentWinner { get; set; }
}
发生这种情况是因为这是您告诉 EF 加载数据的方式。要加载 Auctions 和 WinningAuctions 属性,您需要指定您想要包含然后使用 Include
方法(这称为 Eagerly Loading)显式地包含:
var usertest = db.Users.Include(u => u.WinningAuctions).Include(u => u.Auctions).FirstOrDefault(u => u.Username == "Albert" && u.SiteName == "localhost");
如果您将集合属性更改为 virtual
,则无需执行包含。
public class UserModel
{
public virtual List<AuctionModel> Auctions { get; set; }
public virtual List<AuctionModel> WinningAuctions { get; set; }
}
任何虚拟集合都将延迟加载,除非您特别标记它们。
如果您想详细了解 EF 如何加载数据以及如何配置它,请查看此 link。
更新
如果延迟加载行为仍然不起作用,您需要检查您的模型 类 是否满足需要 EF 创建代理的条件 类。看看这个link.
问题 war 只是两个集合应该是 ICollection<> 而不是 IList<>
我有两个类
public class AuctionModel
{
[Key]
public int Id { get; set; }
public virtual UserModel Seller { get; set; }
public string SellerUsername { get; set; }
public string SellerSiteName { get; set; }
public string CurrentWinnerUsername { get; set; }
public string CurrentWinnerSiteName { get; set; }
public virtual UserModel CurrentWinner { get; set; }
}
和
public class UserModel : Base
{
[Key]
[Column(Order = 2)]
public string Username { get; set; }
[Key]
[Column(Order = 1)]
public string SiteName { get; set; }
public virtual SiteModel Site { get; set; }
public List<AuctionModel> Auctions { get; set; }
public List<AuctionModel> WinningAuctions { get; set; }
}
而 Fluent Api 将关系指定为
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Entity<AuctionModel>()
.HasRequired(a => a.Seller)
.WithMany(u => u.Auctions)
.HasForeignKey(a => new {a.SellerUsername, a.SellerSiteName});
modelBuilder.Entity<AuctionModel>()
.HasOptional(a => a.CurrentWinner)
.WithMany(u => u.WinningAuctions)
.HasForeignKey(a => new {a.CurrentWinnerSiteName, a.CurrentWinnerUsername});
}
据我所知,这应该可以正常工作,但实际情况是 UserModel.Auctions 和 CurrentModel.WinningAuctions 始终为空。我知道对象已附加,因为我检查过并且即使在我将对象保存到数据库后关系也为空。
更新:
return context.Users.Include("MyAuctions").Include("WinningAuctions").First(u => u.Username == userName && u.SiteName == siteName);
使用 Includes 加载数据,加载关系。这在某种程度上是可以预料的,但即使我将关系更改为
public virtual List<AuctionModel> MyAuctions { get; set; }
public virtual List<AuctionModel> WinningAuctions { get; set; }
我仍然必须使用 Include,否则我会得到 null。这对我来说真的没有意义。
所以我不完全确定如何使用 Fluent API 解决此问题,但以下是使用数据注释的方法:
public class AuctionModel
{
[Key]
public int Id { get; set; }
[Required, ForeignKey("Seller"), Column(Order = 2)]
public string SellerUsername { get; set; }
[Required, ForeignKey("Seller"), Column(Order = 3)]
public string SellerSiteName { get; set; }
[ForeignKey("CurrentWinner"), Column(Order = 4)]
public string CurrentWinnerUsername { get; set; }
[ForeignKey("CurrentWinner"), Column(Order = 5)]
public string CurrentWinnerSiteName { get; set; }
public virtual UserModel Seller { get; set; }
public virtual UserModel CurrentWinner { get; set; }
}
发生这种情况是因为这是您告诉 EF 加载数据的方式。要加载 Auctions 和 WinningAuctions 属性,您需要指定您想要包含然后使用 Include
方法(这称为 Eagerly Loading)显式地包含:
var usertest = db.Users.Include(u => u.WinningAuctions).Include(u => u.Auctions).FirstOrDefault(u => u.Username == "Albert" && u.SiteName == "localhost");
如果您将集合属性更改为 virtual
,则无需执行包含。
public class UserModel
{
public virtual List<AuctionModel> Auctions { get; set; }
public virtual List<AuctionModel> WinningAuctions { get; set; }
}
任何虚拟集合都将延迟加载,除非您特别标记它们。
如果您想详细了解 EF 如何加载数据以及如何配置它,请查看此 link。
更新
如果延迟加载行为仍然不起作用,您需要检查您的模型 类 是否满足需要 EF 创建代理的条件 类。看看这个link.
问题 war 只是两个集合应该是 ICollection<> 而不是 IList<>