EF 不更新相关实体,只更新简单字段
EF doesn't updated related entities, only simple fields
我在 EF 6.1 中使用 codeFirst 和独立关联
EF 不会更新分离的实体。 Attach 和 StateModified 对 Related(FK) 实体没有帮助。
添加新实体和更新不相关的属性可以正常工作。
问题出在哪里?
我有主要实体 CoachTransaction :
public class CoachTransaction : BaseEntity
{
public DateTime? TransactionDate { get; set; }
public int? Season { get; set; }
public virtual CoachPosition Position { get; set; }
public virtual Institution StartInstitution { get; set; }
public virtual Institution EndInstitution { get; set; }
}
它的映射:
public MapCoachTransaction()
{
ToTable("CoachTransactions");
HasKey(x => x.Id);
Property(x => x.Id).HasColumnName("TransactionId");
Property(x => x.TransactionDate);
HasOptional(x => x.Position).WithMany().Map(x => x.MapKey("CoachPositionId"));
HasOptional(x => x.StartInstitution).WithMany().Map(x => x.MapKey("StartInstitutionId"));
HasOptional(x => x.EndInstitution).WithMany().Map(x => x.MapKey("EndInstitutionId"));
}
相关实体如下所示:
public class Institution : BaseEntity
{
public virtual InstitutionType InstitutionType { get; set; }
public string Name { get; set; }
public string ImageUrl { get; set; }
}
相关实体的映射:
public MapInstitution()
{
ToTable("Institution");
HasKey(x => x.Id);
Property(x => x.Id).HasColumnName("InstitutionId");
HasOptional(x => x.InstitutionType).WithMany(x => x.Institutions).Map(x => x.MapKey("InstitutionTypeId"));
Property(x => x.Name).HasColumnName("InstitutionName");
Property(x => x.ImageUrl).HasColumnName("InstitutionImageUrl");
}
用法是这样的:
using (var context = new CoachDBContext())
{
IGenericRepository<CoachTransaction> repository = new GenericRepository<CoachTransaction>(context);
coachTransaction.Seasion = 100; // this works
coachTransaction.EndInstitution = newInstitution; this doesnt'
repository.Update(coachTransaction); // coachTransaction comes from POST to Controller
repository.Save();
}
和 repository.Updarte 方法当然使用 Attach:
public virtual void Update(TEntity entityToUpdate)
{
EntitySet.Attach(entityToUpdate);
dbContext.Entry(entityToUpdate).State = EntityState.Modified;
}
使用此设置,SQL 请求如下所示:
exec sp_executesql N'UPDATE [dbo].[CoachTransactions]
SET [TransactionDate] = @0, [Season] = @1
WHERE ([TransactionId] = @2)
',N'@0 datetime2(7),@1 int,@2 int',@0='2015-04-21 20:40:38.1840996',@1=100,@2=24
因此,没有要更新的 endInstitution 实体。
但是如果我在保存前请求这个实体:
using (var context = new CoachDBContext())
{
IGenericRepository<CoachTransaction> repository = new GenericRepository<CoachTransaction>(context);
var coachTransaction = repository.GetById(coachTransaction.Id) // this fixes problem, but not acceptable in this case
coachTransaction.Season = 100;
coachTransaction.EndInstitution = newInstitution; // now this will work
repository.Update(coachTransaction); // coachTransaction comes from POST to Controller
repository.Save();
}
并且 SQL 将包含相关键,例如:
exec sp_executesql N'UPDATE [dbo].[CoachTransactions]
SET [TransactionDate] = @0, [Season] = @1,
[EndInstitution] = @2
WHERE ([TransactionId] = @3)
',N'@0 datetime2(7),@1 int,@2 int, @3 int',@0='2015-04-21 20:40:38.1840996',@1=100,@2=2,@3=24
P.S.
此外,外键关联方法的使用解决了这个映射问题:
Property(x => x.PositionId).HasColumnName("CoachPositionId");
Property(x => x.StartInstitutionId).HasColumnName("StartInstitutionId");
Property(x => x.EndInstitutionId).HasColumnName("EndInstitutionId");
HasRequired(x => x.Position).WithMany().HasForeignKey(x => x.PositionId);
HasRequired(x => x.StartInstitution).WithMany().HasForeignKey(x => x.StartInstitutionId);
HasRequired(x => x.EndInstitution).WithMany().HasForeignKey(x => x.EndInstitutionId);
但这会导致另一个问题,当我在更新相关实体时必须设置两个属性而不是一个属性,例如:
updatingObject.EndInstitution = existingInstitution2;
updatingObject.EndInstitutionId = existingInstitution2.Id;
而不是一个电话:
updatingObject.EndInstitution = existingInstitution2;
它还需要无用的 Id 属性。从我的角度来看,这看起来是错误的。
有什么解决办法吗?
Attach 方法不附加子实体。为此,您需要附加所有要更新的从属目标。
您可以使用 GraphDiff 来更新完整图表而不附加实体。用法是这样的:
使用 (var con
text = new TestDbContext())
{
// Update the company and state that the company 'owns' the collection Contacts.
context.UpdateGraph(company, map => map
.OwnedCollection(p => p.Contacts, with => with
.AssociatedCollection(p => p.AdvertisementOptions))
.OwnedCollection(p => p.Addresses)
);
context.SaveChanges();
}
这是框架的 brief introduction。
此外,我一直在查看 Entity Framework 的源代码并找到了一种方法来实际更新实体,如果你知道密钥 属性 在另一种情况下你需要检查 AddOrUpdate 实现:
public void Update(T item)
{
var entity = _collection.Find(item.Id);
if (entity == null)
{
return;
}
_context.Entry(entity).CurrentValues.SetValues(item);
}
希望对您有所帮助!
我在 EF 6.1 中使用 codeFirst 和独立关联 EF 不会更新分离的实体。 Attach 和 StateModified 对 Related(FK) 实体没有帮助。 添加新实体和更新不相关的属性可以正常工作。 问题出在哪里?
我有主要实体 CoachTransaction :
public class CoachTransaction : BaseEntity
{
public DateTime? TransactionDate { get; set; }
public int? Season { get; set; }
public virtual CoachPosition Position { get; set; }
public virtual Institution StartInstitution { get; set; }
public virtual Institution EndInstitution { get; set; }
}
它的映射:
public MapCoachTransaction()
{
ToTable("CoachTransactions");
HasKey(x => x.Id);
Property(x => x.Id).HasColumnName("TransactionId");
Property(x => x.TransactionDate);
HasOptional(x => x.Position).WithMany().Map(x => x.MapKey("CoachPositionId"));
HasOptional(x => x.StartInstitution).WithMany().Map(x => x.MapKey("StartInstitutionId"));
HasOptional(x => x.EndInstitution).WithMany().Map(x => x.MapKey("EndInstitutionId"));
}
相关实体如下所示:
public class Institution : BaseEntity
{
public virtual InstitutionType InstitutionType { get; set; }
public string Name { get; set; }
public string ImageUrl { get; set; }
}
相关实体的映射:
public MapInstitution()
{
ToTable("Institution");
HasKey(x => x.Id);
Property(x => x.Id).HasColumnName("InstitutionId");
HasOptional(x => x.InstitutionType).WithMany(x => x.Institutions).Map(x => x.MapKey("InstitutionTypeId"));
Property(x => x.Name).HasColumnName("InstitutionName");
Property(x => x.ImageUrl).HasColumnName("InstitutionImageUrl");
}
用法是这样的:
using (var context = new CoachDBContext())
{
IGenericRepository<CoachTransaction> repository = new GenericRepository<CoachTransaction>(context);
coachTransaction.Seasion = 100; // this works
coachTransaction.EndInstitution = newInstitution; this doesnt'
repository.Update(coachTransaction); // coachTransaction comes from POST to Controller
repository.Save();
}
和 repository.Updarte 方法当然使用 Attach:
public virtual void Update(TEntity entityToUpdate)
{
EntitySet.Attach(entityToUpdate);
dbContext.Entry(entityToUpdate).State = EntityState.Modified;
}
使用此设置,SQL 请求如下所示:
exec sp_executesql N'UPDATE [dbo].[CoachTransactions]
SET [TransactionDate] = @0, [Season] = @1
WHERE ([TransactionId] = @2)
',N'@0 datetime2(7),@1 int,@2 int',@0='2015-04-21 20:40:38.1840996',@1=100,@2=24
因此,没有要更新的 endInstitution 实体。
但是如果我在保存前请求这个实体:
using (var context = new CoachDBContext())
{
IGenericRepository<CoachTransaction> repository = new GenericRepository<CoachTransaction>(context);
var coachTransaction = repository.GetById(coachTransaction.Id) // this fixes problem, but not acceptable in this case
coachTransaction.Season = 100;
coachTransaction.EndInstitution = newInstitution; // now this will work
repository.Update(coachTransaction); // coachTransaction comes from POST to Controller
repository.Save();
}
并且 SQL 将包含相关键,例如:
exec sp_executesql N'UPDATE [dbo].[CoachTransactions]
SET [TransactionDate] = @0, [Season] = @1,
[EndInstitution] = @2
WHERE ([TransactionId] = @3)
',N'@0 datetime2(7),@1 int,@2 int, @3 int',@0='2015-04-21 20:40:38.1840996',@1=100,@2=2,@3=24
P.S.
此外,外键关联方法的使用解决了这个映射问题:
Property(x => x.PositionId).HasColumnName("CoachPositionId");
Property(x => x.StartInstitutionId).HasColumnName("StartInstitutionId");
Property(x => x.EndInstitutionId).HasColumnName("EndInstitutionId");
HasRequired(x => x.Position).WithMany().HasForeignKey(x => x.PositionId);
HasRequired(x => x.StartInstitution).WithMany().HasForeignKey(x => x.StartInstitutionId);
HasRequired(x => x.EndInstitution).WithMany().HasForeignKey(x => x.EndInstitutionId);
但这会导致另一个问题,当我在更新相关实体时必须设置两个属性而不是一个属性,例如:
updatingObject.EndInstitution = existingInstitution2;
updatingObject.EndInstitutionId = existingInstitution2.Id;
而不是一个电话: updatingObject.EndInstitution = existingInstitution2;
它还需要无用的 Id 属性。从我的角度来看,这看起来是错误的。 有什么解决办法吗?
Attach 方法不附加子实体。为此,您需要附加所有要更新的从属目标。 您可以使用 GraphDiff 来更新完整图表而不附加实体。用法是这样的: 使用 (var con
text = new TestDbContext())
{
// Update the company and state that the company 'owns' the collection Contacts.
context.UpdateGraph(company, map => map
.OwnedCollection(p => p.Contacts, with => with
.AssociatedCollection(p => p.AdvertisementOptions))
.OwnedCollection(p => p.Addresses)
);
context.SaveChanges();
}
这是框架的 brief introduction。
此外,我一直在查看 Entity Framework 的源代码并找到了一种方法来实际更新实体,如果你知道密钥 属性 在另一种情况下你需要检查 AddOrUpdate 实现:
public void Update(T item)
{
var entity = _collection.Find(item.Id);
if (entity == null)
{
return;
}
_context.Entry(entity).CurrentValues.SetValues(item);
}
希望对您有所帮助!