从EF中的集合中删除项目-奇怪的问题

时间:2019-01-07 15:56:25

标签: c# asp.net-mvc entity-framework

我正在与一个实体框架项目合作,在这个项目中我正在努力从我的一个收藏夹中删除一个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”都从数据库中删除了,没有错误。

最诚挚的问候

4 个答案:

答案 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)

在我看来,您需要添加另一个流利的电话,以定义SlotTimesResto的关系。

根据您的描述,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相关的表已适当更改,以考虑到记录的删除。

编辑:其他答案更详细,比我的要好得多。