使用代码修复“DELETE语句与REFERENCE约束冲突”错误

时间:2014-02-03 08:47:20

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

我有一个Asp.Net MVC 5网站,其中包含EntityFramework Code First。在我的网站中,我有一个Restaurant模型,其中包含以下代码:

public class Restaurant
{
    [Required]
    public string Name { get; set; }

    //....
    public virtual IList<RestaurantType> Types { get; set; }
}

RestaurantType的代码是:

public class RestaurantType
{
    [Key]
    public int ID { get; set; }

    [Required]
    public string Type { get; set; }

    public virtual Restaurant Restaurant { get; set; }
}

当我尝试从上下文中删除restaurant时,出现以下错误:

The DELETE statement conflicted with the REFERENCE constraint "FK_dbo.RestaurantTypes_dbo.Restaurants_Restaurant_ID". The conflict occurred in database "aspnet-Test-20131111052251", table "dbo.RestaurantTypes", column 'Restaurant_ID'. The statement has been terminated.

我有生产中的数据,我想尽可能安静地处理这个问题。我尝试了以下代码:

            for (int i = 0; i < restaurant.Types.Count; i++)
            {
                var type = restaurant.Types[i];
                db.RestaurantTypes.Remove(type);
                restaurant.Types.Remove(type);
            }

            db.Restaurants.Remove(restaurant);
            await db.SaveChangesAsync();

但我得到同样的错误。我检查了数据库,没有餐馆ID的行。我甚至试过这个:

        var list = db.RestaurantTypes.Where(t => t.Restaurant == null || t.Restaurant.ID == restaurant.ID);
        foreach (var ib in list)
        {
            db.RestaurantTypes.Remove(ib);
        }
        db.SaveChanges();

它也没用。有没有办法让我用C#代码解决这个问题?

2 个答案:

答案 0 :(得分:6)

根据您的型号,删除可能实际上并未删除RestaurantTypes中的行。请尝试使用 DeleteObject (请参阅Entity Framework .Remove() vs. .DeleteObject())。另外为了确保在删除所有RestaurantTypes之前没有删除Restaurant,请尝试在删除所有RestaurantTypes后提交更改:

for (int i = 0; i < restaurant.Types.Count; i++)
{
    var type = restaurant.Types[i];
    db.DeleteObject(type);
    restaurant.Types.Remove(type);
}
db.SaveChanges();

db.DeleteObject(restaurant);
db.SaveChanges();

另外,在旁注(这与您的错误消息无关):数据库模型中的关系不是向后的。如果餐厅可以有一个或多个餐厅类型,您应该有从餐厅到餐厅类型的参考。这意味着您需要一个包含关系的附加表(例如RelRestaurantRestaurantType):

---------------                      ------------------                          ------------------ 
|             |                      | Rel            |                          |                |
| Restaurant  | <-- Restaurant_ID -- | Restaurant     | -- RestaurantType_ID --> | RestaurantType |
|             |                      | RestaurantType |                          |                |
---------------                      ------------------                          ------------------

你这样做的方式,每家餐厅都有自己的类型副本。例如。假设你有一个“中国人”类型,你有100家中国餐馆。然后,您最终会在餐厅餐厅中输入100个“中文”条目。

答案 1 :(得分:0)

对您的逻辑(餐厅和餐厅类型)提出异议,餐厅应该是餐厅类型的孩子。

您要做的是级联删除 为了得到这个,你应该在两个表中都有键

public class Restaurant{
    public Restaurant()
    {
        Types=new List<RestaurantType>();
    }
    [Key]
    public int Id{get; set;}
    [Required]
    public string Name{get; set;}

    public virtual ICollection<RestaurantType> Types{get;set;}
}

public class RestaurantType{
   [Key]
   public int Id{get;set;}
   [Required]
   public string Type{get; set;}
   public int RestaurantId{get; set;}

   [ForeignKey("RestaurantId")]
   public Restaurant Restaurant{get;set;}    
}

并且您的代码将正确执行 但请确保您的逻辑是正确的,实际上我知道餐厅只有一种类型,而不是很多

问候