Я предполагаю, что вы работаете с отложенной загрузкой - ваши навигационные свойства Team.Person
и Person.Team
помечены как virtual
в ваших классах сущностей.В результате ваши методы GetTeam
и GetPerson
точно не возвращают Team
и Person
объекты, но являются экземплярами динамически созданных прокси-классов, которые являются производными от этих объектов.Этот динамический прокси-сервер поддерживает отложенную загрузку, что означает, что EF пытается загрузить коллекции навигации Team.Person
и Person.Team
при первом обращении к ним.Это происходит в вашем методе AddPersonToTeam
, когда вы вызываете Add
для этих коллекций.
Теперь проблема заключается в том, что прокси создаются в контексте, который вы немедленно размещаете в своих методах GetTeam
и GetPerson
(в конце использования блока).Прокси-серверы сохранили ссылку на этот контекст внутри и будут использовать этот контекст для загрузки коллекций навигации из базы данных.
Поскольку эти контексты уже удалены, вы получите исключение.
Вам следует изменить дизайннемного кода: не создавайте новый контекст в ваших методах репозитория GetTeam
и GetPerson
.Вместо этого вы должны использовать один и тот же контекст для всех операций: получение Team
, получение Person
и добавление отношения.Например:
public static void AddPersonToTeam(int TeamId, int PersonId)
{
using (var ef = new korfballReportEntities())
{
var team = GetTeam(ef, TeamId);
var person = GetPerson(ef, PersonId);
team.Person.Add(person);
//person.Team.Add(team); <- not necessary, EF will handle this
ef.SaveChanges();
}
}
public static Team GetTeam(korfballReportEntities ef, int id)
{
var q = from l in ef.Team
where l.Id == id
select l;
return q.Single();
}
public static Person GetPerson(korfballReportEntities ef, int id)
{
var query = from p in ef.Person
where p.Id == id
select p;
return query.Single();
}
Другой подход состоит в том, чтобы сделать ваш «Репозиторий» / «Сервис» не статичным, внедрить контекст в конструктор и затем использовать этот контекст во всем хранилище.Тогда вам не нужно передавать контекст в каждый метод.Черновой набросок:
using (var ef = new korfballReportEntities())
{
var repository = new MyRepository(ef);
repository.AddPersonToTeam(int TeamId, int PersonId);
}
public class MyRepository
{
private readonly korfballReportEntities _ef;
public MyRepository(korfballReportEntities ef)
{
_ef = ef;
}
public void AddPersonToTeam(int TeamId, int PersonId)
{
var team = GetTeam(TeamId);
var person = GetPerson(PersonId);
team.Person.Add(person);
_ef.SaveChanges();
}
public Team GetTeam(int id)
{
var q = from l in _ef.Team
where l.Id == id
select l;
return q.Single();
}
public Person GetPerson(int id)
{
var query = from p in _ef.Person
where p.Id == id
select p;
return query.Single();
}
}
Редактировать
Одна небольшая вещь о настройке производительности: в этом конкретном случае ленивая загрузка не является необходимой и более беспокоящей.Это вызывает загрузку (потенциально длинную) коллекцию team.Person
, когда вы хотите добавить только одну дополнительную Person
в коллекцию.Вы можете отключить отложенную загрузку для этой конкретной операции (я ссылаюсь на мой второй пример):
using (var ef = new korfballReportEntities())
{
//switch lazy loading off, only in this single context
ef.Configuration.LazyLoadingEnabled = false;
var repository = new MyRepository(ef);
repository.AddPersonToTeam(int TeamId, int PersonId);
}
public void AddPersonToTeam(int TeamId, int PersonId)
{
var team = GetTeam(TeamId);
var person = GetPerson(PersonId);
// if lazy loading is off, the collecton is null, so we must instantiate one
if (team.Person == null)
team.Person = new List<Person>();
team.Person.Add(person);
_ef.SaveChanges();
}