2

我有一双简单的类在EF 4.1生成代码第一次数据库:EF代码优先 - 多属性指向另一个表

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

注意,当我读到的购买记录后,我得到purchase.User是空的例外 - 那就是,在.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明确显示出现问题的位置。

没有导航属性:

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

,并与导航性能:

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

注意它是如何拉的用户ID,但与User_UserId联接和左连接,不会少。 SalespersonUserId在连接中甚至没有被引用。写入记录后在数据库内部设置UserId,但User_UserID为空。因此,没有什么可以加入,并且我们为包含用户得到空值。

在我看来,这是EF中的一个错误,但它可能有一个设计原因。如果是这样,有人可以为我清除它,也许可以描述一些可以解决它的流利的API?我对我的导航属性有些偏爱。

+0

只是好奇:什么是性能Purchase.UserId和Purchase.SalesPersonUserId的目的是什么?这不是那种多余的信息,因为购买时还有可以找到Id的User和SalesPersonUser的引用?我之前没有看到过这样的设置... –

+1

这就是您如何使用EF Database First从数据库中生成的类,这正是我正在做的。我有一个3层系统,在服务器端有一个数据库,使用并提供从数据库生成的类的Web服务,以及使用Web服务的WPF客户端。 – user1689571

回答

2

EF有问题与您的导航属性 - 这就是为什么它产生额外的FK的。

尝试添加该流利的映射,所以找你明确地映射到FK NAV财产关系:

 modelBuilder.Entity<Purchase>() 
      .HasOptional(p => p.SalespersonUser) 
      .WithMany() 
      .HasForeignKey(p => p.SalespersonUserId); 

     modelBuilder.Entity<Purchase>() 
      .HasRequired(p => p.User) 
      .WithMany() 
      .HasForeignKey(p => p.UserId); 
+0

是的!我刚刚得到相同的代码工作,当你的答案进来。很高兴我想我终于明白了。谢谢! – user1689571

+0

“EF在您的导航属性上遇到问题......”您会说这是一个错误吗? – user1689571

+0

不是一个错误,而是来自发生器的混淆 - 它无法根据约定找出它,所以你只是想让你清除它。 –