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

本文关键字:方法 关系 实体 框架 改变 | 更新日期: 2023-09-27 18:15:39

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

方法1:

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

问题:

这似乎是有效的,但效率非常低,因为对company1.Employees的引用为company1加载了所有员工,对company2.Employees的引用为company2加载了所有员工。

方法2:

employee.Company = company2;

问题:

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

方法3:

employee.CompanyId = company2.Id;

问题:

对我来说,这不会改变数据库中CompanyId列的值。它仍然是原来的值。

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


编辑:

现在不止一个人告诉我,我的方法1没有加载所有相关的雇员。但我对它做了多次测试,证明确实如此。我甚至创建了一个简单的测试应用程序。这是我的代码。

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.RankingsICollection<>类型,而不是IQueryable<>类型。

延迟加载与此完全无关。延迟加载仅仅意味着直到代码引用该集合(或引用相关表中的数据的任何其他属性)时才加载集合。但是一旦代码引用了这个集合,所有相关的实体都会被加载。

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

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

我通常做方法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