更新不同类型但具有相同基数的记录 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 为通用实体添加更改跟踪机制。

来源:Microsoft docs

更新:

你可以试试这个: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();
}