Entity Framework сохраняет дубликаты одной стороны во многих - PullRequest
1 голос
/ 09 марта 2012

У меня проблема с Entity Framework в моем приложении MVC 3.У меня есть таблица пользователей, которая заполняется новой строкой пользователя только тогда, когда сущность машины создается пользователем, который ранее не создавал никаких машин, т.е. она создает только тех пользователей, которых раньше не видела.Каждый пользователь принадлежит к сектору (подразделению компании), который также должен быть установлен до сохранения пользователя и машины.У меня есть сектор по умолчанию, которому назначаются новые пользователи (так что это может быть изменено позже).

У меня есть некоторый код в моем классе контроллера машин для создания новых машин, который выглядит следующим образом:

    [HttpPost]
    public ActionResult Create(Machine machine)
    {
        if (ModelState.IsValid)
        {
            // work out if the user exists in the database already
            var users = userRepository.All.Where(u => u.Username == machine.User.Username);
            if (users.Count() == 0)
            {
                // if the user entry doesn't exist we have to create it assigning a default sector
                Sector defaultSector = null;
                var defaultSectors = sectorRepository.All.Where(s => s.IsDefaultForNewUsers);
                if (defaultSectors.Count() == 0)
                {
                    // jebus! no default sector, so create one
                    defaultSector = new Sector() { Name = "Default", IsDefaultForNewUsers = true };
                    sectorRepository.InsertOrUpdate(defaultSector);
                    sectorRepository.Save();
                }
                else
                {
                    defaultSector = defaultSectors.First();
                }

                machine.User.Sector = defaultSector;
            }
            else
            {
                machine.User = users.First();
            }

            machineRepository.InsertOrUpdate(machine);
            machineRepository.Save();
            return RedirectToAction("Index");
        }
        else
        {
            ViewBag.PossibleInstalledOS = installedosRepository.All;
            ViewBag.PossibleLicenceTypes = licencetypeRepository.All;
            ViewBag.PossibleUsers = userRepository.All;
            return View();
        }
    }

[Edit] Вот тело метода InsertOrUpdate из моего репозитория Machine:

    public void InsertOrUpdate(Machine machine)
    {
        if (machine.MachineId == default(int)) {
            // New entity
            context.Machines.Add(machine);
        } else {
            // Existing entity
            context.Entry(machine).State = EntityState.Modified;
        }
    }

Проблема, с которой я сталкиваюсь с этим кодом, заключается в том, что при сохранении машины онпродолжает создавать нового пользователя, даже если этот пользователь уже находится в системе.Строка, которая находит пользователя, работает и извлекает пользователя, как я и ожидал, но структура сущностей, кажется, не понимает, что я хочу использовать этого пользователя, которого я нашел, а не создавать нового.Так что на данный момент у меня в таблице пользователей несколько идентичных пользователей (кроме ID).Мне нужен один ко многим, чтобы несколько машин принадлежали одному и тому же пользователю.

Кто-нибудь знает, как я заставляю структуру сущностей уважать, что там уже есть пользователь, которого я хочу связать с новыммашина к?

Ответы [ 2 ]

2 голосов
/ 11 марта 2012

Вы не опубликовали код для вашего метода InsertOrUpdate, но я подозреваю, что именно в этом проблема. Могу поспорить, что в этом методе в какой-то момент вы делаете что-то эквивалентное:

context.Machines.Add(machine);

Когда вы вызываете DbSet.Add (или изменяете состояние объекта на Добавленный), вы фактически добавляете весь граф в контекст. Этот процесс остановится, когда встретится с объектом, который отслеживается контекстом. Таким образом, если у вас есть машинный объект, который ссылается на пользовательский объект, и ни один из этих объектов не отслеживается контекстом, то и машинный объект, и пользовательский объект будут добавлены в контекст и окажутся в состоянии «Добавлен». EF затем вставит их обе как новые строки в базу данных.

Что вам нужно сделать, о чем говорилось в другом ответе, это убедиться, что EF знает, что существующий объект пользователя существует в базе данных, убедившись, что его состояние не изменилось (или, возможно, не изменено) и не добавлено, когда Вы экономите.

Существуют различные способы сделать это, и трудно понять, какой из них лучше для вас, не видя больше того, как работают ваше приложение и репозиторий. Один из способов - убедиться, что контекст, используемый для запроса пользователя, совпадает с контекстом, используемым для сохранения. Таким образом, EF уже будет отслеживать существующий объект пользователя и не будет добавлять его при вызове Add.

Другой способ - сообщить вашему хранилищу как-то, является ли пользовательский объект новым. Часто люди используют первичный ключ, чтобы определить это - нулевой ключ указывает на новый объект, ненулевой указывает на существующий объект. Вы также можете передать флаг в свой репозиторий.

Затем вы можете вызвать Add, чтобы добавить график, но затем установить состояние объекта User в значение «Без изменений» (или «Изменено», если оно могло быть изменено с момента запроса), если это существующий пользователь. Это не позволит EF вставить нового пользователя в базу данных.

1 голос
/ 09 марта 2012

Можете ли вы дважды проверить, что ваши репозитории используют один и тот же контекст данных? Если нет, то вы по существу добавляете новую сущность User к machineRepository. В качестве альтернативы вы можете присоединить пользователя к контексту для хранилища компьютера, но вы, вероятно, продолжите сталкиваться с ошибками, подобными этим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...