我想修改实体Payment对象,包含未修改的现有Currency对象并将其保存到EF数据库:
public Payment()
{
int Id {get;set;}
public int Value {get;set;}
public Currency SelectedCurrency{get;set;}
}
public Currency()
{
int Id {get;set;}
string Name;
}
我的编辑方法如下所示:
public override void Edit(MwbePaymentMethod payment)
{
if (payment.Currency != null && payment.Currency.Id != 0 && Context.Entry(payment.UserData).State != EntityState.Unchanged)
{
Context.Entry(payment.Currency).State = EntityState.Unchanged;
}
Context.Entry(payment).State = EntityState.Modified;
}
关于Edit方法的一些说法:它将包含的子实体Currency更改为Unchanged,因为它不会被更新。但是当行
Context.Entry(payment).State = EntityState.Modified;
调用,显示错误:
附加类型'付款'的实体失败,因为同一类型的另一个实体已具有相同的主键值。这个可以 使用'附加'方法或设置状态 实体到'未改变'或者'修改'如果图中有任何实体 冲突的关键值。这可能是因为一些实体是新的和 尚未收到数据库生成的键值。在这种情况下使用 '添加'方法或“添加”#39;实体状态跟踪图形和 然后将非新实体的状态设置为“未更改”#39;或者'修改'如 合适的。
我也尝试使用DbSet.Attach(payment)
方法,但它也会出错。
ADDED1: 这是我调用Edit方法的外部方法。它调用Context.Save并按Id读取Payment实体。
public void UpdateMwbePaymentMethod(MwbePaymentFilter filter, MwbePaymentDtoInOut mwbepayment)
{
var currentPayment = paymentMethodRepository.FindBy(x => x.UserData.Id == filter.userId && x.Id == filter.id);
if (currentPayment==null || currentPayment.Count() != 1)
{
throw new DBConcurrencyException();
}
var mwbePayment = Mapper.Map<MwbePayment>(mwbepayment);
mwbePayment.UserData = userRepository.Get(filter.userId).Data;
paymentRepository.Edit(mwbePayment);
paymentRepository.SaveChanges();
}
ADDED2: 我将AsNoTracking添加到两个查询查询中。我被称为补救措施。但是现在标记为Detached的其他实体,当调用方法DbSet.Attach(payment)时,它会给出错误
附加类型为&#39; MobileWallet.Common.Repository.MwbeAddress&#39;的实体失败,因为同一类型的另一个实体已具有相同的主键值。使用&#39;附加&#39;方法或将实体的状态设置为“未更改”#39;或者&#39;修改&#39;如果图中的任何实体具有冲突的键值。这可能是因为某些实体是新的并且尚未收到数据库生成的键值。在这种情况下,请使用&#39;添加&#39;方法或“添加”#39;实体状态跟踪图形,然后将非新实体的状态设置为“未更改”。或者&#39;修改&#39;酌情。
增加3: 添加方法FindBy:
public IEnumerable<TEntity> FindBy(Expression<Func<TEntity, bool>> predicate, params Expression<Func<TEntity, object>>[] includes)
{
IQueryable<TEntity> query = DbSet.AsNoTracking().Where(predicate);
if (null != includes)
{
foreach (var include in includes)
{
query = query.AsNoTracking().Include(include);
}
}
IEnumerable<TEntity> result = query.AsEnumerable();
return result;
}
答案 0 :(得分:0)
EF6通常非常擅长猜测需要提交给DB的内容以及不需要的内容。 我通常使用这样的代码:
Payment payment = context.Payment.Find( 42 ); //get payment with id 42 from db
payment.Value = 199;
context.SaveChanges(); //only changed data is saved
<强>更新强> 一个更详细的例子:
<强>的DbContext:强>
class TestContext : DbContext
{
public TestContext()
: base()
{}
public DbSet<ParentEntity> Parent { get; set; }
public DbSet<ChildEntity> Child { get; set; }
}
家长实体:
class ParentEntity
{
[Key]
public int Id { get; protected set; }
public string Property1 { get; set; }
public string Property2 { get; set; }
public virtual ChildEntity child { get; set; } // virtual to enable lazy loading
}
儿童实体:
class ChildEntity
{
[Key]
public int Id { get; set; }
public string Value1 { get; set; }
public string Value2 { get; set; }
}
测试代码:
using ( TestContext context = new TestContext( ) )
{
context.Database.Log = Console.WriteLine;
ParentEntity p1 = new ParentEntity( );
p1.Property1 = "Value of P1";
p1.Property2 = "Value of P2";
ChildEntity c1 = new ChildEntity( );
c1.Value1 = "V1";
c1.Value2 = "V2";
p1.child = c1;
context.Parent.Add( p1 );
context.SaveChanges( );
myEntity = p1.Id;
}
using( TestContext context = new TestContext() )
{
context.Database.Log = Console.WriteLine;
ParentEntity p = context.Parent.Where( x => x.Id == myEntity ).FirstOrDefault( );
p.Property1 = "Changed";
p.Property2 = "Value of P2";
context.SaveChanges( );
}
执行的sql:
于2015年4月28日08:49:40 +02:00开始交易
INSERT [dbo]。[ChildEntities]([Value1],[Value2])VALUES(@ 0,@ 1) SELECT [Id] FROM [dbo]。[ChildEntities] WHERE @@ ROWCOUNT&gt; 0 AND [Id] = SCOPE_IDENTITY()
- @ 0:'V1'(Type = String,Size = -1) - @ 1:'V2'(Type = String,Size = -1) - 执行时间为2015年4月28日08:49:41 +02:00 - 在3 ms内完成,结果为:SqlDataReader
INSERT [dbo]。[ParentEntities]([Property1],[Property2],[child_Id]) VALUES(@ 0,@ 1,@ 2)SELECT [Id] FROM [dbo]。[ParentEntities] WHERE @@ ROWCOUNT&gt; 0 AND [Id] = scope_identity()
- @ 0:'P1的值'(Type = String,Size = -1) - @ 1:'P2的值'(Type = String,Size = -1) - @ 2:'2'(Type = Int32) - 执行时间为2015年4月28日08:49:41 +02:00 - 在3 ms内完成,结果为:SqlDataReader
承诺交易于28.04.2015 08:49:41 +02:00封闭连接 于28.04.2015 08:49:41 +02:00于28.04.2015 08:49:41开通 02:00
选择 [Limit1]。[Id] AS [Id], [Limit1]。[Property1] AS [Property1], [Limit1]。[Property2] AS [Property2], [Limit1]。[child_Id] AS [child_Id] FROM(选择TOP(1) [Extent1]。[Id] AS [Id], [Extent1]。[Property1] AS [Property1], [Extent1]。[Property2] AS [Property2], [Extent1]。[child_Id] AS [child_Id] FROM [dbo]。[ParentEntities] AS [Extent1] WHERE [Extent1]。[Id] = @ p__linq__0 )AS [Limit1]
- p__linq__0:'2'(Type = Int32,IsNullable = false) - 执行时间为2015年4月28日08:49:41 +02:00 - 在0 ms内完成,结果为:SqlDataReader
2015年4月28日08:49:41 +02:00关闭连接打开连接 28.04.2015 08:49:41 +02:00于28.04.2015 08:49:41 +02:00开始交易
UPDATE [dbo]。[ParentEntities] SET [Property1] = @ 0 WHERE([Id] = @ 1)
- @ 0:'已更改'(Type = String,Size = -1) - @ 1:'2'(Type = Int32) - 执行时间为2015年4月28日08:49:41 +02:00 - 在5毫秒内完成,结果:1
承诺交易于28.04.2015 08:49:41 +02:00封闭连接 于28.04.2015 08:49:41 +02:00
从SQL-Log可以看出,只更新了更改的属性。
注意:'Changed'也意味着分配给相同的值。因此,如果您从TextBox
更新,请在分配之前检查值是否已更改。
的更新强>
EF6似乎真正跟踪了这些变化 - 具有相同值的赋值不会触发更新 - 请参阅更新的代码