【问题标题】:The relationship could not be changed because one or more of the foreign-key properties is non-nullable on saving无法更改关系,因为一个或多个外键属性在保存时不可为空
【发布时间】:2016-04-14 12:01:32
【问题描述】:

我使用GraphDiff 更新分离的对象图,并且在保存父对象及其子对象时出现上述异常。

模型和映射是:

public class Group
{
    public int Id { get; set; }
    public virtual ICollection<GroupUser> Users{ get; set; }
}

public class GroupUser
{
    public int Id { get; set; }
    public int GroupId { get; set; }
    public int UserId { get; set; }
    public virtual User User { get; set; }
}

public class GroupMap : EntityTypeConfiguration<Group>
{
    public GroupMap()
    {
        this.ToTable("groups");
        this.HasKey(t => t.Id).Property(t => t.Id).HasColumnName("id").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

        this.HasMany(t => t.Users)
            .WithOptional()
            .HasForeignKey(d => d.GroupId)
            .WillCascadeOnDelete();
    }
}

public class GroupUserMap : EntityTypeConfiguration<GroupUser>
{
    public GroupUserMap ()
    {
        this.ToTable("groups_users");
        this.HasKey(t => t.Id).Property(t => t.Id).HasColumnName("id").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        this.Property(t => t.GroupId).HasColumnName("group_id").IsRequired();
        this.Property(t => t.UserId).HasColumnName("user_id").IsRequired();

        this.HasRequired(t => t.User)
            .WithMany()
            .HasForeignKey(d => d.UserId)
            .WillCascadeOnDelete(false);
    }
}

对于插入和更新,我的存储库中有以下方法:

public override Group Update(Group entity)
{
    if (entity.Users != null)
    {
        entity.Users.ToList()
                    .ForEach(x =>
                    {
                        x.GroupId = x.Id == 0 ? 0 : entity.Id;
                        x.UserId = x.User.Id;
                    });
    }

    return dbContext.UpdateGraph<Group>
        (entity,
            map => map.OwnedCollection(x => x.Users, with => with.AssociatedEntity(c => c.Users))
        );
}

我执行以下操作:

  1. 添加新组,保存并重新加载
  2. 将用户添加到组,保存并重新加载
  3. 添加第二个用户,保存并重新加载
  4. 添加第三个用户,尝试保存 -> 抛出异常

在调试时,添加的用户实体的状态始终是分离的,对于新实体,GroupIdId 都设置为 0。添加的前 2 个用户已成功保存。但是,在第三个中,抛出异常。

如果,我总是使用相同的方法进行保存,为什么它并不总是有效?是EF 还是GraphDiff 问题,有没有办法解决这个问题?

关于 SO 和其他地方的大多数问题和相关答案都涉及删除子实体的情况。在我的特定场景中不是这种情况。

【问题讨论】:

    标签: c# entity-framework entity-framework-6 graphdiff


    【解决方案1】:

    您是否尝试过在不被 EF 跟踪时查看实体状态是否正在被修改?

    试试

    db.Entry(currentUser).State = EntityState.Modified;
    

    ToList() 函数也可能导致您意外修改用户状态。

    【讨论】:

    • ToList() 更改为普通的 foreach 没有任何区别。
    • 如果添加了“状态”并且没有更改,这听起来像是实体断开连接的问题。我的猜测是 EF 正在重新创建“GroupUser”,然后在尝试保存时将之前的“GroupUser”置空。您是否尝试打印之前添加的用户的值?
    【解决方案2】:

    可能与不可为空的 UserId 有关。如您所知,EF 使用 UserId 来编写 User。如果 User 为空(它可以) EF 不能写入实体。 它也可能与 EF 用来映射 Group.Users 集合的 User.GroupId 相关。

    另外,我无法理解您的模型。 一个用户只有一个组。 一个组可以有多个用户。

    如果这是真的,你为什么不简化你的模型删除关联实体? EF不需要...

    public class Group
    {
        public int Id { get; set; }
        public virtual ICollection<User> Users{ get; set; }
    }
    
    public class User
    {
        public int Id { get; set; }
        public virtual Group Group { get; set; }
    }
    

    在这种情况下,您只需要 UserMap。

    public class UserMap : EntityTypeConfiguration<User>
    {
        public UserMap()
        {
            // You don't need to set primary key. EF take Id and create an identity column
            //HasKey(t => t.Id); 
    
            // Table & Column Mappings
            ToTable("users");
            // No column mappings in this case.
    
            // Relationships
            HasRequired(t => t.Group)
                .WithMany(t => t.Users)
                .Map(d => d.MapKey("user_group"));
    
        }
    }
    

    如果一个用户可以拥有多个组,您可以通过这种方式修改您的用户模型

    public class User
    {
        public int Id { get; set; }
        public virtual ICollection<Group> Groups { get; set; }
    }
    

    EF 理解是多对多关系,将创建关联表(UsersGroups)但您不需要关联实体。

    编辑

    您很少需要使用 EF6 设置 db.Entry(myEntity).State = EntityState.Modified;。代理效果很好。

    【讨论】:

      【解决方案3】:

      请试试这个。虽然它未经测试

      public override Group Update(Group entity)
      {
          if (entity.Users != null)
          {
              foreach(var user in entity.Users){
                user.GroupId = x.Id == 0 ? 0 : entity.Id;
                user.UserId = x.User.Id;
               dbContext.Entry(child).State = EntityState.Modified;
              }
      
          }
      
          return dbContext.UpdateGraph<Group>
              (entity,
                  map => map.OwnedCollection(x => x.Users, with => with.AssociatedEntity(c => c.Users))
              );
      }
      

      【讨论】:

        猜你喜欢
        • 2015-12-16
        • 2013-10-19
        • 2014-04-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多