ef-Code-First一对多可选删除抛出异常:无法删除主键值

时间:2014-01-03 18:02:42

标签: c# entity-framework ef-code-first one-to-many

我已经查看并找不到什么接缝是一个简单的事情的解决方案,我有3个实体当我尝试删除城市我得到这个例外:

System.Data.Entity.Infrastructure.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.Entity.Core.UpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlServerCe.SqlCeException: The primary key value cannot be deleted because references to this key still exist. [ Foreign key constraint name = FK_dbo.User_dbo.District_DistrictId ]

我想要达到的目标是: 当我删除一个城市时,所有儿童区都要删除,而不是用户。 当我删除一个区时,只删除该区。 当我删除用户时,仅删除用户。

    • 一个城市可以拥有0-N个区域并将删除级联
    • 区域必须拥有城市并且具有可选的0 - N个用户
  1. 用户
    • 用户可以选择0 - 1区
  2. 实体用户

    public class User
    {
      public Guid UserId { get; set; }
    
      public virtual District District { get; set; }
      public Guid? DistrictId { get; set; }
     }
    

    实体城市

    public class City 
    {
        public Guid CityId { get; set; }
    
        public virtual ICollection<District> Districts { get; set; }
    }
    

    实体区

    public class District 
    {
        public Guid DistrictId { get; set; }
    
        public City City { get; set; }
        public Guid CityId { get; set; }
    
        public virtual ICollection<User> Users { get; set; }
    }
    //EntityTypeConfiguration
       HasRequired(d => d.City)
                .WithMany(c => c.Districts)
                .HasForeignKey(d => d.CityId)
                .WillCascadeOnDelete(true); 
    
        HasMany(d=> d.Users)
                .WithOptional(u=> u.District)
                .HasForeignKey(u=> u.DistrictId)
                .WillCascadeOnDelete(false);
    

    我尝试在用户映射中放置此配置,但没有任何更改相同的错误

    HasOptional(u => u.District)
                .WithMany(d => d.Users)
                .HasForeignKey(u => u.DistrictId)
                .WillCascadeOnDelete(false);
    

    我也在使用Sqlce4和EF6以及Generic Unit of Work & Repositories Framework

    感谢您的帮助

    此致

2 个答案:

答案 0 :(得分:1)

您必须将DistrictId的{​​{1}}外键设置为User,以避免在尝试删除null或{时违反约束条件{1}}。如果相关的City未加载到上下文中,EF将不会自动执行此操作。

要删除区域,您可以这样做:

District

删除城市:

Users

Cacsading delete会关注在这里删除这些区域。但是,我不确定在这种情况下,加载用户的// "Include" because you need the users to nullify their FKs to the district var district = context.Districts.Include(d => d.Users) .SingleOrDefault(d => d.DistrictId == someDistrictId); if (district != null) { // "Remove" will set the FKs of the LOADED users to null context.Districts.Remove(district); context.SaveChanges(); } 是否会设置为var city = context.Cities.Include(c => c.Districts.Select(d => d.Users)) .SingleOrDefault(c => c.CityId == someCityId); if (city != null) { context.Cities.Remove(city); context.SaveChanges(); } 。如果它不起作用,你必须手动完成:

DistrictId

答案 1 :(得分:1)

谢谢大家,以为EF足够聪明,可以处理像这样的简单任务。 所以不仅要清除区域,不仅仅是城市,这里是我最终使用这个存储库来工作的方式

  var city = _unitOfWork.Repository<City>().Query()
            .Include(c => c.Districts.Select(d => d.Users))
            .Filter(c => c.CityName.Equals(cityName, StringComparison.InvariantCultureIgnoreCase))
            .Get().FirstOrDefault();

        if (city != null)
        {
            var districts = city.Districts.ToList();
            for (var i = districts.Count - 1; i >= 0; i--)
            {
                var users = districts[i].Users.ToList();
                for (var j = users.Count - 1; j >= 0; j--)
                {
                    users[j].DistrictId = null;
                    users[j].ObjectState = ObjectState.Modified;

                    _unitOfWork.Repository<User>().Update(users[j]);
                }
                districts[i].Users.Clear();
                _unitOfWork.Repository<District>().Delete(districts[i]);
            }
            _unitOfWork.Repository<City>().Delete(city);

很糟糕但是很有效