Соединительная таблица Elides, как мне вставить строку, не запрашивая базу данных для объектов, на которые ссылается строка?

Допустим, у нас есть простая схема:

Employee
--------
Id
EmployeeName


Project
-------
Id
ProjectName


EmployeeProject
---------------
EmployeeId
ProjectId

Я помню, что в предыдущей версии EF в модель добавлялась соединительная таблица (или, может быть, она всегда опускалась, и я думаю о таблице с дополнительными столбцами). В EF 6 таблица опущена, и модель выглядит так:

Модель EF

Есть ли способ добавить строки в соединительную таблицу без предварительного запроса к базе данных, чтобы получить соответствующий объект? Например, если я хочу создать новый проект, я могу получить список идентификаторов сотрудников из внешнего интерфейса; Мне пришлось бы запросить базу данных, чтобы получить сотрудников, а затем добавить их в коллекцию сотрудников проекта, а затем снова нажать на базу данных, чтобы сохранить. Есть ли способ сделать это с помощью только одного обращения к базе данных?

Обновить

Вот пример того, что я пытаюсь решить (псевдокод):

CreateProject (string name, List<int> employeeIds)
{
    var proj = new Project;
    proj.ProjectName = name;
    context.Projects.Add(proj);

    foreach(var id in employeeIds)
    {
        // we have the id, but we need to get the actual Employee entity by hitting the database
        var employee = context.Employees.First(e => e.Id == id); 
        proj.Employees.Add(employee);
    }

    context.SaveChanges();
}

Если бы в модели существовала соединительная таблица, я мог бы просто сделать:

CreateProject (string name, List<int> employeeIds)
{
    var proj = new Project;
    proj.ProjectName = name;
    context.Projects.Add(proj);

    foreach(var id in employeeIds)
    {
        var empProj = new EmployeeProject();
        empProj.Project = proj;

        // we don't have the Employee entity, but we can set the Id and everything works.
        empProj.EmployeeId = id;  

        context.EmployeeProjects.Add(empProj);
    }

    context.SaveChanges();  // only need to hit database once, after all entities have been added
}

person Turch    schedule 11.08.2014    source источник


Ответы (2)


Вам не нужно сначала извлекать элементы. При работе с отключенным объектом вы можете просто присоединить существующую сущность или изменить состояние на Unchanged.

Entity Framework заботится об отслеживании состояния сущностей, когда они подключены к контексту, но в сценариях с отключением или N-уровневых сценариев вы можете сообщить EF, в каком состоянии должны находиться ваши сущности.

Подробнее: http://msdn.microsoft.com/en-us/data/jj592676

Вы можете просто прикрепить сотрудника, чтобы уменьшить круговой обмен базой данных.

foreach(var id in employeeIds)
{
    var employee = new Employe { Id = id }; 
    db.Set<Employee>().Attach(employee); // context.Entry(employee).State = EntityState.Unchanged;
    proj.Employees.Add(employee);
}
person Yuliam Chandra    schedule 11.08.2014
comment
Потрясающе, это именно то, что я искал. - person Turch; 11.08.2014

EF позаботится обо всем за вас; вы можете игнорировать это. Просто добавьте сотрудника в коллекцию Project.Employees и/или проект в коллекцию Employee.Projects, и он возьмет для вас категорию соединительной таблицы. То же самое при удалении: просто удалите объекты из коллекций, и строки таблицы соединений будут удалены.

РЕДАКТИРОВАТЬ после уточнения: если вы работаете с объектами EF, экземпляр существующего объекта EF должен быть получен через EF. При использовании EF вы не ведете список идентификаторов сотрудников; вы ведете список сотрудников. EF отслеживает то, о чем он знает: если вы просто создадите пустой объект и заполните его, EF подумает, что это новый объект.

person simon at rcl    schedule 11.08.2014
comment
В том-то и дело, что мне нужно сделать вызов в базу данных, чтобы получить сущность Employee из идентификатора. Если бы кратность была равна 1 на стороне проекта (то есть в Project был столбец EmployeeId), я мог бы установить либо Project.Employee, либо Project.EmployeeId, в зависимости от того, что у меня было в наличии. Я добавил к вопросу пример кода, который более четко показывает проблему. - person Turch; 11.08.2014
comment
Ваш псевдокод выглядит правильно. Какую проблему это доставляет вам? - person simon at rcl; 11.08.2014
comment
Извините: я смотрел на второй пример с объектом EmployeeProject6: это неправильно и не будет работать, поскольку модель не имеет класса EmployeeProject (но знает, что таблица существует). Первый набор псевдокода выглядит нормально. Какую проблему это доставляет вам? - person simon at rcl; 11.08.2014
comment
Эта строка var employee = context.Employees.First(e => e.Id == id); делает вызов к базе данных. Вопрос спрашивает, как вставить строку без запроса к базе данных объектов, на которые ссылается строка?. Второй образец сделает это, но, как вы сказали, этого класса не существует. - person Turch; 11.08.2014
comment
ХОРОШО. Мне это было непонятно. Если вы работаете с объектами EF, экземпляр существующего объекта EF необходимо получить через EF. При использовании EF вы не ведете список идентификаторов сотрудников; вы ведете список сотрудников. - person simon at rcl; 11.08.2014
comment
Хорошо, круто, поэтому ответ невозможен. Если вы измените свой, чтобы сказать что-то в этом роде, я соглашусь :) Кроме того, теперь я вижу соответствующую документацию: вы можете использовать один или оба типа ассоциаций в своей модели. Однако если у вас чистое отношение «многие ко многим», которое связано с помощью таблицы соединений, содержащей только внешние ключи, EF будет использовать независимую ассоциацию для управления таким отношением «многие ко многим» (источник). Кажется странным, что они дали бы вам выбор в одном случае, но не в другом. - person Turch; 11.08.2014