我正在与一个实体框架项目合作,在这个项目中我正在努力从我的一个收藏夹中删除一个Item。 首先,我通过以下方式在对象“ 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; }
}
由于我与该对象有其他关系(请参阅“应用程序用户”中的一个),因此我也使用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,请尝试不要删除我的对象,而只是保留它并将其ID设置为Null ...这不是我期望的
操作失败:由于一个或多个外键属性不可为空,因此无法更改关系。对关系进行更改时,相关的外键属性将设置为空值。如果外键不支持空值,则必须定义新的关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象
我觉得我的关系对于EF而言配置正确。我想正确地进行添加和删除关系... 您认为这可能来自流畅的配置吗?
顺便说一句,一旦我删除了“ Resto”,我的级联删除工作就很好了,所有我的项目“ OpeningTimes”都从数据库中删除了,没有错误。
最诚挚的问候
答案 0 :(得分:4)
如果您希望能够通过父实体(OpeningTimes
)修改子实体(Resto
),则需要在模型构建器中指定两者之间的关系:>
modelBuilder.Entity<Resto>()
.HasMany(r => r.OpeningTimes)
.WithOptional()
.HasForeignKey(ot => ot.RestoId)
This blog post详细介绍了如何处理这种情况。
另一种方法是直接从DbContext上定义的DbSet中直接删除实体:
DbManager.SlotTimes.Remove(slotTime);
答案 1 :(得分:1)
您可以尝试以下方法吗:
DbManager.Entry(slotTime).State = EntityState.Deleted;
await DbManager.SaveChangesAsync();
答案 2 :(得分:1)
在我看来,您需要添加另一个流利的电话,以定义SlotTimes
与Resto
的关系。
根据您的描述,SlotTime
完全取决于Resto
:您不能拥有与SlotTime
不相关的Resto
。但是,显然EF
不能仅仅推断出这一点:您将不得不以流畅的配置来说明这一点。
因为它太复杂了,所以我不能从内存中重新创建它,而且我不在装有VS的计算机上。但我认为您应该从以下开始:
modelBuilder.Entity<Resto>()
.HasMany<TimeSlot>(r => r.OpeningTimes)
.WithOne(t => t.Resto)
....
很抱歉无法为您填写整个通话。
顺便说一句,这个问题有一个很好的答案,可以解释所有问题:EF 4: Removing child object from collection does not delete it - why?
答案 3 :(得分:0)
当您删除slotTime时,是否还有另一个表具有与OpeningTimes表相关的外键?似乎您要删除该项目,并且相关表正在尝试将外键设置为null,这是不允许的。您需要确保与OpeningTimes相关的表已适当更改,以考虑到记录的删除。
编辑:其他答案更详细,比我的要好得多。