Обновление записей другого типа, но с одинаковым базовым классом - PullRequest
0 голосов
/ 20 февраля 2020

Я пытаюсь обновить записи другого типа, но все они основаны на одном и том же базовом типе, BaseEntity (у которого OwnerId среди его членов)

Это сделано, чтобы я может передать право владения записями всех таблиц от одного пользователя другому.

Вот что мне нужно далеко:

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 не отслеживается контекстом.

Я мог бы использовать имя таблицы для приведения объекта к его реальному типу, но тогда мне нужно было бы сделать что-то вроде:

Context.MyTable1.Attach(entity);

Но это теряет свою общую привлекательность; Мне бы пришлось обратиться ко всей таблице явно.

Я помню, в более старой версии EF вы могли бы сделать что-то вроде Context.ChangeTracker.Attach(entity), но этого, похоже, уже нет.

Есть идеи?

Ответы [ 2 ]

1 голос
/ 21 февраля 2020

В EF Core DbContext есть метод Attach, но в EF DbSet есть метод Attach (Object entity). Вы должны использовать DbSet, чтобы добавить механизм отслеживания изменений в свой объект c.

источник: Документы Microsoft

Обновление:

Вы можете попробовать это: context.Set(entity.GetType()).Attach(entity)

0 голосов
/ 21 февраля 2020

Я закончил тем, что сделал:

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();
}
...