У меня есть проблема, которая меня беспокоила в течение нескольких часов, я смог сузить ее до точного кода, но я не могу похоже, делают какой-то дальнейший прогресс, я до сих пор довольно новичок в EF6, поэтому я не могу быть на 100% актуальным для лучших практик.Entity Framework 6 Проверка электронной почты причины «Привязка сущности не удалось»
У меня есть модель пользователя;
public class User
{
public Guid ID { get; set; }
[DisplayName("Display Name")]
[Required]
public string DisplayName { get; set; }
[DisplayName("Email Address")]
[DataType(DataType.EmailAddress, ErrorMessage = "Please enter a valid email address")]
[Required]
public string EmailAddress { get; set; }
public string Company { get; set; }
[DisplayName("Internal ID")]
public string InternalId { get; set; }
[DisplayName("User Status")]
public UserStatus Status { get; set; }
[DisplayName("Access Request Notifications")]
public bool SendNotifications { get; set; }
[DisplayName("Admin")]
public bool IsAdmin { get; set; }
public virtual ICollection<Transaction> Submissions { get; set; }
}
В моих взглядах пользователей в пределах базы данных будут перечислены и отображаться пользователю, это все работает замечательно.
В моем действии «Создать» на контроллере пользователя ([HTTP-сообщение]), я запускаю проверку ниже, чтобы узнать, существует ли уже существующий в базе данных почтовый адрес, и если он это делает, он возвращает сообщение обратно пользователю, информирующему их и запрещающему создание пользователя.
public ActionResult Create([Bind(Include = "DisplayName,EmailAddress,Company,InternalId,Status,SendNotifications,IsAdmin")] User user)
{
try
{
user.ID = Guid.NewGuid();
if (ModelState.IsValid)
{
var existingUser = db.Users.FirstOrDefault(x => x.EmailAddress.Equals(user.EmailAddress, StringComparison.InvariantCultureIgnoreCase));
if(existingUser == null)
{
db.Users.Add(user);
db.SaveChanges();
return RedirectToAction("Index");
}
else
{
StaticConfig.Trace.Trace(SFTraceEvents.DbFailedAddingUser1, string.Format("User with email address '{0}' already exists in database", user.EmailAddress));
ViewData.Add("DbError", string.Format("Creation failed. User with email address '{0}' already exists", user.EmailAddress));
}
}
}
catch (Exception ex)
{
StaticConfig.Trace.Trace(SFTraceEvents.DbFailedAddingUser1, ex);
ViewData.Add("DbError", "Unable to create user, an internal error has occured. Please try again, if the problem persists, please contact your system administrator.");
}
return View(user);
}
Этот процесс хорошо работает, я не использую встроенный в 'Find() метод, так как это, кажется, только для поиска по первичному ключу сущности, и я хочу, чтобы найти на нечто иное, чем ПК ,
Когда я пытаюсь реализовать ту же логику в методе Edit, я сталкиваюсь с приведенной ниже ошибкой.
Исключение: [InvalidOperationException: System.InvalidOperationException: привязка объекта типа Models.User не удалась, поскольку другой объект того же типа уже имеет такое же значение первичного ключа. Это может произойти при использовании метода «Прикрепить» или установки состояния объекта в «Без изменений» или «Модифицировано», если любые объекты на графике имеют конфликтующие значения ключей. Это может быть связано с тем, что некоторые объекты являются новыми и еще не получили значения ключей базы данных. В этом случае используйте метод «Добавить» или «Добавленное» состояние объекта для отслеживания графика, а затем, если необходимо, установите состояние не новых объектов «Без изменений» или «Модифицировано».
Моего Изменить способ кода в настоящее время следующий:
public ActionResult Edit([Bind(Include = "ID,DisplayName,EmailAddress,Company,InternalId,Status,SendNotifications,IsAdmin")] User user)
{
try
{
if (ModelState.IsValid)
{
var existingUser = db.Users.FirstOrDefault(x => x.EmailAddress.Equals(user.EmailAddress, StringComparison.InvariantCultureIgnoreCase));
if(existingUser == null || existingUser.ID.Equals(user.ID))
{
db.Entry(user).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
else
{
StaticConfig.Trace.Trace(SFTraceEvents.DbFailedUpdatingUser2, user.DisplayName, string.Format("Email address '{0}' already exists in database", user.EmailAddress));
ViewData.Add("DbError", string.Format("Unable to save changes, email address '{0}' already exists", user.EmailAddress));
}
}
}
catch(Exception ex)
{
StaticConfig.Trace.Trace(SFTraceEvents.DbFailedUpdatingUser2, user.DisplayName, ex);
ViewData.Add("DbError", "Unable to save changes, an internal error has occured. Please try again, if the problem persists, please contact your system administrator.");
}
return View(user);
}
Так я проверяю, чтобы видеть, есть ли существующий пользователь с адресом электронной почты, который был введен на странице редактирования, я тогда проверку чтобы убедиться, что идентификатор пользователя, редактируемого, совпадает с идентификатором пользователя, находящегося в базе данных, если это так, то, конечно, тот же адрес электронной почты должен быть разрешен, так как мы редактируем пользователя, которому принадлежит этот адрес. Если, однако, идентификаторы разные, то в базе данных есть другой пользователь, используя адрес электронной почты, который был введен на странице редактирования.
Если я удалю 'var existingUser' и последующий оператор if(), который выполняет проверки идентификатора, то редактирование проходит через штраф, но тогда я рискую иметь несколько пользователей с тем же адресом электронной почты в системе , Когда я верну чек, я получаю исключение выше.
У кого-нибудь есть предложения по поводу того, что я могу делать неправильно .... есть ли более эффективный способ проверить объекты, которые могут уже содержать определенные данные?
Редактировать Я обнаружил, что в EF6.1, он поддерживает «индекс» аннотацию данных, который, кажется, чтобы уникальное свойство быть установлены в нем, как хорошо. Мне нужно посмотреть правильно, но это может предложить то, что я ищу.
Я также знаю, что я мог бы сделать некоторые исходные запросы SQL, чтобы решить эту проблему, но, если это возможно, я хотел бы избежать этого.
Кроме того, уникальные ограничения были отбирали раненый и помечены как отложенный: «Update: это функция была отложена и не будет включена в Entity Framework 5 », довольно круто, если она вернулась к EF 6.1 – Claies
Да, я использую EF 6.1, поэтому я думал, что они могут быть возможным решением, я использовал ответ ниже, и он работает так же хорошо, похоже, он будет намного более гибким, так что я могу его расширить и добавить дополнительные проверки в будущем, если мне нужно, чтобы –
Возможно, вы можете взглянуть на мой ответ на [ASP.NET MVC - привязка объекта типа «MODELNAME» не удалась, потому что другой объект того же типа уже имеет такое же значение первичного ключа] (http://stackoverflow.com/questions/23201907/asp-net-mvc -attaching-ан-объект-в-типа-ModelName-не удалось, потому-другой-лор/39557606 # 39557606). –