更新不同类型但具有相同基数的记录 class
Updating records of different type, but with same base class
我正在尝试更新不同类型的记录,但所有这些都基于相同的基本类型,BaseEntity
(其成员中有 OwnerId
)
这样做是为了让我可以将所有 table 的记录的所有权从一个用户转移到另一个用户。
这是我目前所要做的:
public ActionResult TransferOwnership(int sourceUserId, int targetUserId)
{
var metadata = ((IObjectContextAdapter)Context).ObjectContext.MetadataWorkspace;
var tables = metadata.GetItems(DataSpace.SSpace).Where(x => x.BuiltInTypeKind == BuiltInTypeKind.EntityType).ToList();
foreach (var table in tables)
{
var tableName = table.GetType().GetProperty("Name").GetValue(table);
List<BaseEntity> entities = Context.Database.SqlQuery<BaseEntity>($"SELECT * FROM {tableName} WHERE OwnerId = {sourceUserId}").ToList();
foreach (var entity in entities)
{
entity.OwnerId = targetUserId;
Context.Entry(entity).State = EntityState.Modified; //this fails
}
if (entities.Count > 0)
Context.SaveChanges();
}
return Ok();
}
在我设置实体状态的那一行,我收到一条错误消息,指出类型 BaseEntity
未被上下文跟踪。
我可以使用 table 名称将对象转换为它的真实类型,但是我需要做类似的事情:
Context.MyTable1.Attach(entity);
但这失去了它的一般吸引力;我必须明确地解决所有 table。
我记得在旧版本的 EF 中,您可以执行类似 Context.ChangeTracker.Attach(entity)
的操作,但它似乎已经消失了。
有什么想法吗?
在 EF Core DbContext 中有 Attach 方法,但在 EF DbSet 中有 Attach(Object entity) 方法。您应该使用 DbSet 为通用实体添加更改跟踪机制。
更新:
你可以试试这个:context.Set(entity.GetType()).Attach(entity)
我最后做了:
public async Task<ActionResult> TransferOwnership(int sourceUserId, int targetUserId)
{
var metadata = ((IObjectContextAdapter)Context).ObjectContext.MetadataWorkspace;
var tables = metadata.GetItems(DataSpace.SSpace).Where(x => x.BuiltInTypeKind == BuiltInTypeKind.EntityType).ToList();
//some entities were cast to their proxy types which were unconvertable with Convert.ChangeType...
Context.Configuration.ProxyCreationEnabled = false;
foreach (var table in tables)
{
var tableName = table.GetType().GetProperty("Name").GetValue(table);
var type = Assembly.GetAssembly(typeof(BaseEntity)).GetTypes().SingleOrDefault(x => x.Name == tableName.ToString());
List<object> entities = await Context.Database.SqlQuery(type, $"SELECT * FROM {tableName} WHERE OwnerId = {sourceUserId}").ToListAsync();
foreach (var entity in entities)
{
var e = entity as BaseEntity;
e.OwnerId = targetUserId;
Context.Set(type).Attach(Convert.ChangeType(e, type));
Context.Entry(e).State = EntityState.Modified;
}
if (entities.Count > 0)
Context.SaveDirect();
}
return Ok();
}
我正在尝试更新不同类型的记录,但所有这些都基于相同的基本类型,BaseEntity
(其成员中有 OwnerId
)
这样做是为了让我可以将所有 table 的记录的所有权从一个用户转移到另一个用户。
这是我目前所要做的:
public ActionResult TransferOwnership(int sourceUserId, int targetUserId)
{
var metadata = ((IObjectContextAdapter)Context).ObjectContext.MetadataWorkspace;
var tables = metadata.GetItems(DataSpace.SSpace).Where(x => x.BuiltInTypeKind == BuiltInTypeKind.EntityType).ToList();
foreach (var table in tables)
{
var tableName = table.GetType().GetProperty("Name").GetValue(table);
List<BaseEntity> entities = Context.Database.SqlQuery<BaseEntity>($"SELECT * FROM {tableName} WHERE OwnerId = {sourceUserId}").ToList();
foreach (var entity in entities)
{
entity.OwnerId = targetUserId;
Context.Entry(entity).State = EntityState.Modified; //this fails
}
if (entities.Count > 0)
Context.SaveChanges();
}
return Ok();
}
在我设置实体状态的那一行,我收到一条错误消息,指出类型 BaseEntity
未被上下文跟踪。
我可以使用 table 名称将对象转换为它的真实类型,但是我需要做类似的事情:
Context.MyTable1.Attach(entity);
但这失去了它的一般吸引力;我必须明确地解决所有 table。
我记得在旧版本的 EF 中,您可以执行类似 Context.ChangeTracker.Attach(entity)
的操作,但它似乎已经消失了。
有什么想法吗?
在 EF Core DbContext 中有 Attach 方法,但在 EF DbSet 中有 Attach(Object entity) 方法。您应该使用 DbSet 为通用实体添加更改跟踪机制。
更新:
你可以试试这个:context.Set(entity.GetType()).Attach(entity)
我最后做了:
public async Task<ActionResult> TransferOwnership(int sourceUserId, int targetUserId)
{
var metadata = ((IObjectContextAdapter)Context).ObjectContext.MetadataWorkspace;
var tables = metadata.GetItems(DataSpace.SSpace).Where(x => x.BuiltInTypeKind == BuiltInTypeKind.EntityType).ToList();
//some entities were cast to their proxy types which were unconvertable with Convert.ChangeType...
Context.Configuration.ProxyCreationEnabled = false;
foreach (var table in tables)
{
var tableName = table.GetType().GetProperty("Name").GetValue(table);
var type = Assembly.GetAssembly(typeof(BaseEntity)).GetTypes().SingleOrDefault(x => x.Name == tableName.ToString());
List<object> entities = await Context.Database.SqlQuery(type, $"SELECT * FROM {tableName} WHERE OwnerId = {sourceUserId}").ToListAsync();
foreach (var entity in entities)
{
var e = entity as BaseEntity;
e.OwnerId = targetUserId;
Context.Set(type).Attach(Convert.ChangeType(e, type));
Context.Entry(e).State = EntityState.Modified;
}
if (entities.Count > 0)
Context.SaveDirect();
}
return Ok();
}