0

我想更新一个记录类型图,它修改了内部也有的父对象和子对象。当子项的 EF UPDATE 注册表将它们设置为 NULL 时,通常会出现此问题,其中子项有助于识别您正在更新的记录。

我的域类是:

此类帮助我更改状态,添加 - 自定义 - 删除,这是从父级作为所有子级的图表。使它工作的功能。

public interface IObjectWthState
{
    State State { get; set; }
}
public enum State 
{
    Added,
    Unchanged,
    Modified,
    Deleted
}

这是一个用户类:

 public abstract class User : IObjectWthState 
 {
    public int Id { get; set; }
    public String Name { get; set; }
    public String LastName { get; set; }        
    [Timestamp]
    public byte[] RowVersion { get; set; }
    [NotMapped]
    public State State { get; set; }
}

这是从用户继承的两个类:

public class AdminUser:User
{
    public ICollection<BasicUser> UsersList { get; set; }
    public String Email { get; set; }
}

public class BasicUser: User
{
    public String Position { get; set; }
    public String Department { get; set; }
}

正如所见 AdminUser BasicUser 有一个列表。

该模型是根据需要生成的,需要检测外键并添加。这是数据库的图片:

通过迁移生成的模型

这是添加或更新信息的函数:

public virtual void AddUpdateGraph(T entity)
{

    if (((IObjectWthState)entity).State == State.Added)
    {
        DbEntityEntry dbEntityEntry = dbContext.Entry(entity);
        dbEntityEntry.State = EntityState.Added;
    }
    else
    {
        dbSet.Add(entity);
        dbContext.ApplyStateChanges();
    }
} 

处理 go 和调整内部节点状态的函数:

public static void ApplyStateChanges(this DbContext context)
{
    foreach (var entry in context.ChangeTracker.Entries<IObjectWthState>())
    {
        IObjectWthState stateInfo = entry.Entity;
        entry.State = StateHelpers.ConvertState(stateInfo.State);
    }
}  

将状态返回给 EF 的函数:

public static EntityState ConvertState(State state)
{
    switch (state)
    {
        case State.Added:
            return EntityState.Added;
        case State.Modified:
            return EntityState.Modified;
        case State.Deleted:
            return EntityState.Deleted;
        default:
            return EntityState.Unchanged;
    }
}

当您想用他的列表 BasicUser 添加一个新的 AdminUser 时,一切正常,没有问题,当您想修改 EF BasicUser AdminUser 并为 BasicUser 生成更新但添加了外键为空的条件时,问题就来了。

在这里你可以看到生成的两个更新

管理员用户:

 exec sp_executesql N'update [dbo].[User]
set [Name] = @0, [LastName] = @1, [Email] = @2
where (([Id] = @3) and ([RowVersion] = @4))
select [RowVersion]
from [dbo].[User]
where @@ROWCOUNT > 0 and [Id] = @3',N'@0 nvarchar(max) ,@1 nvarchar(max) ,@2 nvarchar(max) ,@3 int,@4 binary(8)',@0=N'Beto',@1=N'Guerere',@2=N'beto@gmail.com',@3=3,@4=0x0000000000000801

基本用户:

exec sp_executesql N'update [dbo].[User]
set [Name] = @0, [LastName] = @1, [Position] = @2, [Department] = @3, [AdminUser_Id] = @4
where ((([Id] = @5) and ([RowVersion] = @6)) and [AdminUser_Id] is null)
select [RowVersion]
from [dbo].[User]
where @@ROWCOUNT > 0 and [Id] = @5',N'@0 nvarchar(max) ,@1 nvarchar(max) ,@2 nvarchar(max) ,@3 nvarchar(max) ,@4 int,@5 int,@6 binary(8)',@0=N'Viomar',@1=N'Guerere',@2=N'Supervisora',@3=N'Ventas',@4=3,@5=4,@6=0x0000000000000802

正如您在 EF 生成的 SQL 命令中看到的那样,添加了对 BasicUser 进行更新的记录条件具有 Null 值到 AdminUser_Id。我不明白这是为什么。该字段不能为空,因为该用户已分配给主管。

我希望我解释了。

非常感谢你能给我的任何帮助。

4

2 回答 2

0

回答我的问题:EF 相信数据库中的 FK 无论如何你都必须在模型中与她一起工作,作为这种形式的变量,如果你断开连接工作,你要确保你的信息被存储。

必须做的第一件事是在类 BasicUser 中添加一个 int 类型的变量,我们将称之为 AdminUser_Id:

public class BasicUser: User
    {       
        public String Position { get; set; }
        public String Department { get; set; }
        public int AdminUser_Id { get; set; }
    }

然后我们必须告诉 EF 添加的变量是一个 FK,它引用了一个 AdminUser AdminUser 并且可以有多个 BasicUser。

为此,我们在声明上下文的地方,DataLayer(在我的例子中),并在创建模型的地方添加以下注释:

modelBuilder.Entity<AdminUser>()HasMany(A => A.UsersList ).WithRequired().HasForeignKey(B => B.AdminUser_Id );

We update the model and with these adjustments the mistake is eliminated completely at the moment of realizing the update of the record.

有关 FK 和 EF 的更多信息推荐阅读这篇文章:

  1. 使用不存在的外键
  2. 代码优先关系 Fluent API

非常感谢大家,尤其是Julie Lerman的帮助,如果没有它,我会花更多的钱来解决这个问题。

我希望我已经解释过了。

于 2012-11-20T14:38:45.837 回答
0

您是否正在检索已经分配了管理员用户的基本用户?在我看来,从您检索它到您进行更新时,adminuserid 没有被保留。我经常看到这种情况,例如在 MVC 应用程序中,您不想显示该外键,因此您不将其包含在视图中。但是当您更新对象并将其发送到控制器时,它会创建一个具有空 FK 的新用户实例。当您将该 FK 用作并发检查字段时,在从控制器移动到视图再到控制器时,保留该值是非常重要的。如果是这种情况,幸运的是我已经有一篇关于这个问题的博客文章,所以我不必在这里重新解释:http://thedatafarm.com/blog/data-access/round-tripping-a-timestamp-field-with-ef4-1-code-first-and-mvc-3/

让我知道是否确实如此。如果是这样,希望它能解决您的问题。如果没有,我可能会有更多问题!:)

(ps 你的代码的其余部分看起来很熟悉!:) 这来自我和罗文关于 DbContext 的书吗?:) )

于 2012-11-13T16:41:41.843 回答