改变实体框架关系的正确方法
本文关键字:方法 关系 实体 框架 改变 | 更新日期: 2023-09-27 18:15:39
给定一个具有两个表的数据库模式:Company
和Employee
,其中Employee
表具有Company
表的外键,更改特定员工所关联的公司的正确代码是什么?
company1.Employees.Remove(employee);
company2.Employees.Add(employee);
方法2:问题:
这似乎是有效的,但效率非常低,因为对
company1.Employees
的引用为company1
加载了所有员工,对company2.Employees
的引用为company2
加载了所有员工。
employee.Company = company2;
方法3:问题:
引发异常:违反了多重约束。XXX关系中的角色"公司"。FK_Employee_Companies'具有多重性1或0..1.
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.Rankings
是ICollection<>
类型,而不是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