我有一对简单的类在EF 4.1中的Code First中生成数据库:
public class User
{
public int UserId { get; set; }
public string UserName { get; set; }
}
public class Purchase
{
public int PurchaseId { get; set; }
public int UserId { get; set; }
public int? SalespersonUserId { get; set; }
public User User { get; set; }
public User SalespersonUser { get; set; }
}
public class NewItemsDataContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Purchase> Purchases { get; set; }
}
在我的程序中,我创建并写入一些数据。
class Program
{
static void Main(string[] args)
{
Database.SetInitializer<NewItemsDataContext>(new DropCreateDatabaseIfModelChanges<NewItemsDataContext>());
using (NewItemsDataContext sadc = new NewItemsDataContext())
{
sadc.Users.Add(new User());
sadc.SaveChanges();
}
using (NewItemsDataContext sadc = new NewItemsDataContext())
{
sadc.Purchases.Add(new Purchase() { UserId = 1 });
sadc.SaveChanges();
}
using (NewItemsDataContext sadc = new NewItemsDataContext())
{
var sql = sadc.Purchases.Include(p => p.User);
foreach (Purchase purchase in sql)
Console.WriteLine(purchase.User.UserId.ToString());
}
}
}
注意,当我读回购买记录时,我得到一个例外购买。用户为空 - 也就是说.Include没有为用户提取任何内容。现在,如果我忽略了OnModelCreating中的salespersonUser导航属性(或只是将其注释掉):
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Purchase>().Ignore(p => p.SalespersonUser);
base.OnModelCreating(modelBuilder);
}
代码有效,用户加载到.Include。
当忽略SalespersonUser nav属性时,创建的数据库看起来与您期望的一样。 Purchase表具有PurchaseId,UserId和SalespersonId。但是,一旦您重新添加SalespersonUser nav属性(停止忽略它),您最终会在表中再添加两个键:User_UserId和SalespersonUser_UserId(以及原始UserId和SalespersonUserId)。
此外,生成的SQL肯定会显示出现问题的位置。
没有nav属性:
{SELECT
[Extent1].[PurchaseId] AS [PurchaseId],
[Extent1].[UserId] AS [UserId],
[Extent1].[SalespersonUserId] AS [SalespersonUserId],
[Extent2].[UserId] AS [UserId1],
[Extent2].[UserName] AS [UserName]
FROM [Purchases] AS [Extent1]
INNER JOIN [Users] AS [Extent2] ON [Extent1].[UserId] = [Extent2].[UserId]}
并使用nav属性:
{SELECT
[Extent1].[PurchaseId] AS [PurchaseId],
[Extent1].[UserId] AS [UserId],
[Extent1].[SalespersonUserId] AS [SalespersonUserId],
[Extent2].[UserId] AS [UserId1],
[Extent2].[UserName] AS [UserName],
[Extent1].[SalespersonUser_UserId] AS [SalespersonUser_UserId]
FROM [Purchases] AS [Extent1]
LEFT OUTER JOIN [Users] AS [Extent2] ON [Extent1].[User_UserId] = [Extent2].[UserId]}
注意它如何拉取UserId,但是与User_UserId和左连接一起加入,不能少。甚至连接中都没有引用SalespersonUserId。写入记录后,在数据库内部,UserId已设置,但User_UserID为null。因此,没有任何东西可以加入,我们对包含的用户来说是空的。
在我看来,这是EF中的一个错误,但它有可能存在设计原因。如果是这样,有人可以为我清理它,也许可以描述一些可以解决它的流畅API吗?我对我的导航属性有点偏爱。
答案 0 :(得分:2)
EF有导航属性的问题 - 这就是为什么它会产生额外的FK。
尝试添加此流畅映射,因此您明确将FK映射到导航属性关系:
modelBuilder.Entity<Purchase>()
.HasOptional(p => p.SalespersonUser)
.WithMany()
.HasForeignKey(p => p.SalespersonUserId);
modelBuilder.Entity<Purchase>()
.HasRequired(p => p.User)
.WithMany()
.HasForeignKey(p => p.UserId);