Я работаю с проектом фреймворка сущностей, в котором мне трудно удалить элемент из одной из моих коллекций. Сначала у меня есть отношение «Один ко многим», созданное между моим объектом «Resto» и «OpeningTimes» следующим образом: В моей модели:
[Table("Resto")]
public class Resto
{
public int Id { get; set; }
public string Name { get; set; }
public string PhoneNumber { get; set; }
public string Address { get; set; } //TODO Ajouter adresse détaillées
public virtual ICollection<SlotTime> OpeningTimes {get; set;}
public virtual ICollection<ApplicationUser> Administrators { get; set; }
public virtual ICollection<ApplicationUser> Chefs { get; set; }
public virtual Menu Menu {get; set;}
}
[Table("RestoSlotTimes")]
public class SlotTime
{
public int SlotTimeId { get; set; }
public DayOfWeek DayOfWeek { get; set; }
public TimeSpan OpenTime { get; set; }
public TimeSpan CloseTime { get; set; }
public int RestoId { get; set; }
public virtual Resto Resto { get; set; }
}
Поскольку у меня есть другое отношение к этому объекту (см. Одно из приложений User), я также использую язык Fluent для устранения двусмысленностей.
Следующим способом:
modelBuilder.Entity<Resto>()
.HasMany<ApplicationUser>(s => s.Administrators)
.WithMany(c => c.Resto_Admin)
.Map(cs =>
{
cs.MapLeftKey("Resto_Admin");
cs.MapRightKey("Admin");
cs.ToTable("RestosAdmins");
});
modelBuilder.Entity<Resto>()
.HasMany<ApplicationUser>(s => s.Chefs)
.WithMany(c => c.Resto_Chefs)
.Map(cs =>
{
cs.MapLeftKey("Resto_Chefs");
cs.MapRightKey("Chef");
cs.ToTable("RestosChefs");
});
modelBuilder.Entity<Resto>()
.HasOptional(s => s.Menu)
.WithRequired(ad => ad.resto)
.WillCascadeOnDelete(true);
Но эти отношения работают нормально.
Сегодня я выполняю базовые операции на моем «OpeningTimes» в моем контроллере, добавляя элемент в БД со следующим:
[HttpPost]
public async Task<ActionResult> AddSlotTimeToRestaurant(AddSlotTimeToRestaurantView model)
{
var resto = await DbManager.Restos.FirstAsync(r => r.Id == model.RestoId);
if (resto != null)
{
if (model.OpenTimeId < model.CloseTimeId)
{
SlotTime slotTime = new SlotTime()
{
DayOfWeek = model.Day,
OpenTime = model.SlotTimeList.timeSpanViews.FirstOrDefault(m => m.Id == model.OpenTimeId).TimeSpan,
CloseTime = model.SlotTimeList.timeSpanViews.FirstOrDefault(m => m.Id == model.CloseTimeId).TimeSpan
};
resto.OpeningTimes.Add(slotTime);
await DbManager.SaveChangesAsync();
return RedirectToAction("edit", new { id = model.RestoId });
}
else
{
ModelState.AddModelError("SelectedSlotTimeId_1_Stop", "L'heure de fermeture doit être après l'heure d'ouverture");
return View();
}
}
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Этот код работает должным образом. Но теперь я пытаюсь выполнить другую функцию для удаления объекта с помощью следующего кода:
public async Task<ActionResult> RemoveSlotTimeToRestaurant(int RestoId, int SlotId)
{
var resto = await DbManager.Restos.FirstAsync(r => r.Id == RestoId);
if (resto != null)
{
SlotTime slotTime = resto.OpeningTimes.FirstOrDefault(m => m.SlotTimeId == SlotId);
if (slotTime != null)
{
resto.OpeningTimes.Remove(slotTime);
await DbManager.SaveChangesAsync();
return RedirectToAction("edit", new { id = RestoId });
}
}
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
У меня ошибка в строке DbSave ... Там, где похоже, что EF пытается не удалять мой объект, а просто сохранить его и установить для его идентификатора значение Null ... Это не то, что я ожидал
The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted
У меня такое чувство, что мои отношения хорошо настроены для EF. Я чувствую, что правильно добавляю и удаляю отношения ... Как вы думаете, это может происходить из-за быстрой настройки?
Кстати, как только я удаляю «Resto», у меня хорошо работает каскадное удаление, где все мои элементы «OpeningTimes» удаляются из БД без ошибок.
С наилучшими пожеланиями,





Можете ли вы попробовать, как показано ниже:
DbManager.Entry(slotTime).State = EntityState.Deleted;
await DbManager.SaveChangesAsync();
EF будет понимать remove как удаление этой строки и не будет учитывать правило каскада, поэтому он будет иметь значение null в родительской таблице, удалив запись дочерней таблицы. Если каскадное правило установлено правильно и вы хотите удалить средства, основанные на каскадном правиле, вам необходимо указать приведенные выше инструкции. Это применимо к сценариям отношений «один ко многим».
Если вы хотите иметь возможность изменять дочерний объект (OpeningTimes) через родительский объект (Resto), вам необходимо указать связь между ними в построителе модели:
modelBuilder.Entity<Resto>()
.HasMany(r => r.OpeningTimes)
.WithOptional()
.HasForeignKey(ot => ot.RestoId)
Это сообщение в блоге более подробно описывает обработку этого сценария.
Другой подход - просто удалить объект непосредственно из DbSet, определенного в DbContext:
DbManager.SlotTimes.Remove(slotTime);
Привет, devNull. Я пробовал, как вы предложили, плавный подход, но проблема все та же ... То же сообщение об ошибке.
И для второго подхода при этом я не указал slotTime в DbSet. Я получаю к нему доступ только через Resto из его Childs ...
Да, наконец, ваш второй подход кажется правильным. Наконец нашел вот это: weblogs.asp.net/zeeshanhirani/…
Кстати, как я уже сказал выше, "OpeningTimes" недоступен через мой DbManager ... Я верю, потому что noe установлен в DBSet ... Должен ли я объявить его там? Это лучший способ объявить Чайлдс в DbSet?
Мне кажется, вам нужно добавить еще один беглый вызов, чтобы определить, как SlotTimes соотносится с Resto.
Судя по тому, что вы описываете, SlotTime полностью зависит от Resto: у вас не может быть SlotTime, не связанного с Resto. Но, очевидно, EF не может просто сделать такой вывод: вам нужно будет сказать это с быстрой настройкой.
Я не могу воссоздать это по памяти, потому что это слишком сложно, и я не на машине с установленным VS. Но я думаю, вы бы начали с этого:
modelBuilder.Entity<Resto>()
.HasMany<TimeSlot>(r => r.OpeningTimes)
.WithOne(t => t.Resto)
....
Прошу прощения за то, что не смог заполнить за вас весь запрос.
Кстати, на этот другой вопрос есть очень хороший ответ, который все объясняет: EF 4: Удаление дочернего объекта из коллекции не приводит к его удалению - почему?
Спасибо, Энн, действительно, твой подход не сработает (как у devNull). Но вы можете найти ответ дальше по присланной вами ссылке. Здесь доступно полное объяснение weblogs.asp.net/zeeshanhirani/…
@JonathanHalleux Рад, что вы нашли ответ!
Когда вы удаляете slotTime, есть ли другая таблица, у которой есть внешний ключ, связанный с таблицей OpeningTimes? Похоже, что вы удаляете элемент, а связанная таблица пытается установить для внешнего ключа значение null, в котором это запрещено. Вам необходимо убедиться, что таблицы, связанные с OpeningTimes, изменены соответствующим образом, чтобы учесть удаление записи.
Обновлено: другие ответы более подробны, и они намного лучше, чем мои.
Здравствуйте, да, так это работает ... Похоже, EF не понимает "Удалить" как действие "удалить" ;-)