改变实体框架关系的正确方法

时间:2015-10-02 18:24:39

标签: c# .net sql-server entity-framework

给定一个包含两个表的数据库模式:CompanyEmployee,其中Employee表具有Company表的外键,正确的代码是什么?改变与特定员工相关的公司?

方法1:

company1.Employees.Remove(employee);
company2.Employees.Add(employee);
  

问题:

     

这似乎有效,但由于company1.Employees的引用加载了company1的所有员工,并且对company2.Employees的引用加载了{{1}的所有员工,因此非常低效。 }}

方法2:

company2
  

问题:

     

引发异常:违反了多重性约束。角色'公司'关系' XXX.FK_Employee_Companies'具有多重性1或0..1。

方法3:

employee.Company = company2;
  

问题:

     

对我来说,这不会改变数据库中employee.CompanyId = company2.Id; 列的值。它仍具有以前的价值。

我在使用我的方法1 的大型应用程序中使用经过良好测试的代码,并且在找到性能问题后尝试对其进行优化。我知道可能有其他因素影响我得到的结果。我正在寻找能够更深入了解实体框架内部工作原理的人,以建议他们如何处理这一问题。

修改

我已经被不止一个人告知我的方法1 没有加载所有相关员工。但我已经对此进行了多次测试,表明它确实如此。我甚至创建了一个简单的测试应用程序。这是我的代码。

CompanyId

似乎有些人认为第二行只会从var website = context.Websites.FirstOrDefault(); var ranking = website.Rankings.FirstOrDefault(); 表中加载一行。但是,以下是生成的查询:

Rankings

SELECT TOP (1) 
[c].[ID] AS [ID], 
[c].[Title] AS [Title], 
[c].[URL] AS [URL], 
[c].[AliasForID] AS [AliasForID], 
[c].[ActiveState] AS [ActiveState], 
[c].[Alert] AS [Alert]
FROM [dbo].[Website] AS [c]

注意第二个查询。它返回exec sp_executesql N'SELECT [Extent1].[ID] AS [ID], [Extent1].[WebsiteID] AS [WebsiteID], [Extent1].[PageRank] AS [PageRank], [Extent1].[AlexaRank] AS [AlexaRank], [Extent1].[AlexaReach] AS [AlexaReach], [Extent1].[DateAdded] AS [DateAdded] FROM [dbo].[Ranking] AS [Extent1] WHERE [Extent1].[WebsiteID] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1 表中链接到Ranking实体的所有行。它不会过滤只返回第一行。以同样的方式,访问Website以调用company1.Employees方法将加载与Add()相关的所有员工,因为company1的类型为Website.Rankings而不是{{1} }}

延迟加载完全不相关。延迟加载只是意味着在代码引用此集合(或引用相关表中的数据的任何其他属性)之前不会加载集合。但是,一旦代码引用此集合,就会加载所有相关实体。

我希望有人能告诉我这是不真实的,或者如何防止这种情况发生。到目前为止,只有那些说它不真实的人不愿意支持它,或者当我要求他们支持他们的要求时侮辱我。不了解其工作原理会导致严重的性能问题。

1 个答案:

答案 0 :(得分:1)

我通常会执行方法3 ,如果您的实体关系是正确构建的,那么它是正确的。例如,看看这个结构:

public class Employee
{
    public int Id { get; set; }
    //.... Other employee properties like name, last name, etc...

   public int CompanyId {get; set;}

   [ForeignKey("CompanyId")]
   public Company Company { get; set;}
}

public class Company 
{
   public int Id { get; set; }
   //.... Other company properties like name, type, etc...

   public virtual ICollection<Employee> Employees { get; set; }
}

在为员工更改公司后使用DbContext.SaveChanges()应该可以解决问题:

Employee employee = db.Employees.Find(123); // Assume CompanyId = 3 for this employee
employee.CompanyId = 5;
db.SaveChanges(); // Employee's CompanyId should be changed