我想更新记录类型图,它修改父对象和内部也有子对象。当孩子的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有一个列表。
模型是按照需要生成的,需要检测外键并添加。这是DB的图片:
这是添加或更新infromación的功能:
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();
}
}
处理的函数去调整内部节点的状态:
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;
}
}
如果要添加一个新的AdminUser及其列表BasicUser一切正常,没有问题,当您想要修改EF BasicUser AdminUser并为BasicUser生成更新但添加了外键为null的条件时,会出现问题
在这里,您可以看到生成的两个更新
ADMINUSER:
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
BasicUser:
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的更新,记录的条件具有AdminUser_Id的Null值。我不明白这个的原因。该字段不能为空,因为该用户已分配给主管。
我希望我解释一下。
非常感谢您给我的任何帮助。
答案 0 :(得分:0)
您是否正在检索已经分配了adminuser的基本用户?在我看来,从您将其检索到您进行更新时,adminuserid不会被保留。我经常看到这种情况,例如在MVC应用程序中,您不希望显示该外键,因此您不会将其包含在视图中。但是当您更新并将对象发送到控制器时,它会创建一个具有空FK的新用户实例。当您使用该FK作为并发检查字段时,在从控制器移动到视图到控制器时保留该值非常重要。如果是这种情况,幸运的是我已经有关于这个问题的博客文章,所以我不想在这里重新解释:http://thedatafarm.com/blog/data-access/round-tripping-a-timestamp-field-with-ef4-1-code-first-and-mvc-3/
如果确实如此,请告诉我。如果是这样,希望它能解决您的问题。如果没有,我可能会有更多问题! :)
(p.s。其余代码看起来非常熟悉!:)来自我的&amp;罗恩关于DbContext的书? :))
答案 1 :(得分: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,添加的变量是引用AdminUser AdminUser的FK,并且可以有许多BasicUser。
为了做到这一点,我们去了我们声明上下文的地方,DataLayer(在我的情况下),在创建模型的cuncion中我们添加了以下注释:
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的更多信息,建议您阅读本文:
非常感谢所有人特别向Julie Lerman求助,如果没有它,我会花费更多资金来解决这个问题。
我希望我已经解释过了。