Вставка новой записи в таблицу связывания с linq для сущностей с POCO - PullRequest
2 голосов
/ 13 октября 2011

У меня есть стол команды и стол игрока во многих отношениях.Существует таблица ссылок под названием TeamOnPlayer.EF с POCO генерирует свойство навигации, называемое Person для сущности Team, а также генерирует навигацию.двигательныйназывается Team for the People.

Я пытаюсь вставить новую запись в таблицу TeamOnPlayer, но EF и POCO скрывают ее.Я попытался сделать это:

public static void AddPersonToTeam(int TeamId, int PersonId)
    {
        using (var ef = new korfballReportEntities())
        {
            var team = GetTeam(TeamId);
            var person = GetPerson(PersonId);

            team.Person.Add(person);
            person.Team.Add(team);

            ef.SaveChanges();
        }
    }

GetTeam (TeamId) и GetPerson (PersonId) получают правильную команду и человека:

public static Team GetTeam(int id)
    {
        using (var ef = new korfballReportEntities())
        {
            var q = from l in ef.Team
                    where l.Id == id
                    select l;
            return q.Single();
        }
    }
public static Person GetPerson(int id)
    {
        using (var ef = new korfballReportEntities())
        {
            var query = from p in ef.Person
                        where p.Id == id
                        select p;
            return query.Single();
        }
    }

Когда он пытается вызвать команду. Персона.Add (person) выдает исключение:

"Экземпляр ObjectContext был удален и больше не может использоваться для операций, требующих подключения."System.Exception {System.ObjectDisposedException}

Может кто-нибудь, пожалуйста, покажите мне правильный путь?

Редактировать

Теперь я понимаю, в чем проблема, благодаря вам.Я был немного озадачен использованием блоков, которые вы включили.Например, это:

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 static void AddPersonToTeam(int TeamId, int PersonId)
{
    using (var ef = new korfballReportEntities())
    {
        var q = from t in ef.Team
                where t.Id == TeamId
                select t;
        var team =  q.Single();

        var q2 = from p in ef.Person
                where p.Id == PersonId
                select p;
        var person = q2.Single();

        try
        {
            team.Person.Add(person);
            person.Team.Add(team);
        }
        catch (Exception e)
        {  
        }

        ef.SaveChanges();
    }
}

Единственная проблема в том, что я не могу повторно использовать мои методы GetPerson (int id) и GetTeam (int id).

Как вы думаете?Это нормально?Это уродливый способ?

1 Ответ

0 голосов
/ 13 октября 2011

Я предполагаю, что вы работаете с отложенной загрузкой - ваши навигационные свойства 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();
}
...