2015-10-02 1 views
0

Учитывая схему базы данных с двумя таблицами: Company и Employee, где Employee таблица имеет внешний ключ к Company таблице, что правильный код, чтобы изменить компанию конкретный работник, связанный с ?правильный путь, чтобы изменить Entity Framework отношения

Метод 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 и я стараюсь, чтобы оптимизировать его после того, как проблемы с производительностью были найдены. Я понимаю, что могут быть другие факторы, которые влияют на результаты, которые я получаю. Я ищу кого-то с более глубоким пониманием внутренней работы Entity Framework, чтобы предложить, как они подходят к этому.


EDIT:

Я теперь был сказан более чем одним человеком, что мой Метод 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. Он не фильтрует, чтобы возвращать только первую строку. Точно так же доступ к для вызова метода Add() будет загружать всех сотрудников, связанных с company1, поскольку Website.Rankings имеет тип ICollection<>, а не IQueryable<>.

Ленивая нагрузка абсолютно не связана. Ленивая загрузка просто означает, что коллекция не загружается, пока код не ссылается на эту коллекцию (или любое другое свойство, которое ссылается на данные из связанной таблицы). Но как только код ссылается на эту коллекцию, все связанные объекты загружаются.

Я хотел бы, чтобы кто-то показал мне, как это неверно или как предотвратить это. Пока что единственные люди, которые говорят это, неверны, не желают поддерживать это и/или просто оскорблять меня, когда я попросил их поддержать их требования. Непонимание того, как это работает, может привести к серьезным проблемам с производительностью.

+0

Комментарии не для широкого обсуждения; этот разговор был [перемещен в чат] (http://chat.stackoverflow.com/rooms/91230/discussion-on-question-by-jonathan-wood-correct-way-to-change-entity-framework-r) , –

ответ

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 
+0

Это не работает для меня. Это хорошо проверенный код, используя мой метод * 1, и я просто пытаюсь его оптимизировать. Отношения прекрасны, и изменения сохраняются. –

Смежные вопросы