.net 如何更新EF Core中的特定属性?

woobm2wo  于 2022-12-01  发布在  .NET
关注(0)|答案(2)|浏览(264)

我一直在尝试更新EF Core中的特定属性。但仍然遇到异常。
我已尝试将状态设置为detach,但仍出现相同的异常。

public async Task  UpdateSpecificAsync(TEntity entity, params Expression<Func<TEntity, object>>[] updatedProperties)
{
    _context.Entry(entity).State = EntityState.Modified;

    if (updatedProperties.Any())
    {
        foreach (var property in updatedProperties)
        {
            _context.Entry(entity).Property(property).IsModified = true;
        }
    }
          
    await _context.SaveChangesAsync();
}

用法:

await _efUserRepository.UpdateSpecificAsync(userEntity, 
                x => x.Address, x => x.FirstName, x => x.LanguageId, x => x.LastName, x => x.MiddleName);

例外情况:
无法追踪实体类型'User'的执行严修,因为已经在追踪另一个具有相同{'Id'}索引键值的执行严修。附加现有实体时,请确定只附加一个具有指定索引键值的实体执行严修。请考虑使用'DbContextOptionsBuilder.EnableSensitiveDataLogging'来查看恩怨的索引键值。

求解方式

public async Task UpdateSpecificAsync(TEntity entity, params string[] updatedProperties)
        {

            var dbentity = Entities.First(x => x.Id == entity.Id);
            foreach (var property in updatedProperties)
            {
                var newValue = entity.GetType().GetProperty(property).GetValue(entity, null);
                PropertyInfo propertyInfo = dbentity.GetType().GetProperty(property);
                Type t = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType;
                object safeValue = (newValue == null) ? null : Convert.ChangeType(newValue, t);
                propertyInfo.SetValue(dbentity, safeValue, null);
            }
            await _context.SaveChangesAsync();
        }

await _efUserRepository.UpdateSpecificAsync(userModel,
                nameof(User.Address), nameof(User.FirstName), nameof(User.LanguageId), nameof(User.LanguageId), nameof(User.MiddleName));

我不是很满意,但它确实解决了这个问题。

rkue9o1l

rkue9o1l1#

DbContext应该知道您的实体,如果它处于Detached状态,则必须将该实体附加到DbContext。

public async Task  UpdateSpecificAsync(TEntity entity, params Expression<Func<TEntity, object>>[] updatedProperties)
            {
                if (_context.Entry(entity).State == EntityState.Detached && 
                _context.Set<TEntity>().Local.All(e => e.Id != entity.Id))
                {
                    _context.Attach(entity);
                }

                if (updatedProperties.Any())
                {
                    foreach (var property in updatedProperties)
                    {
                        _context.Entry(entity).Property(property).IsModified = true;
                    }
                }
          
                await _context.SaveChangesAsync();
            }
sz81bmfz

sz81bmfz2#

在EF 7中不需要附加实体!只需将更改的属性设置为IsModified = true;

public void UpdateSpecificField(TEntity entity, params Expression<Func<TEntity, object>>[] updatedProperties)
{
    foreach (var property in updatedProperties)
        _context.Entry(entity).Property(property).IsModified = true;
}

使用该方法可以做到:

var oldUser = await _appUow.UserRepo
            .Select(x => new GetUserDto { UserId = x.UserId, Name = x.Name })
            .FirstOrDefaultAsync(x => x.UserId > 1);

        var newUser = new User
        {
            UserId = oldUser.UserId,
            Name = "newName3",
            Code = "code3"
        };

        _appUow.UserRepo.UpdateSpecificField(newUser, x => x.Name, x => x.Code);
        await _appUow.SaveChangesAsync();

则此命令将生成以下tsql:

SELECT TOP(1) [u].[UserId], [u].[Name]
FROM [Base].[User] AS [u]
WHERE [u].[UserId] > 1

SET IMPLICIT_TRANSACTIONS OFF;
SET NOCOUNT ON;
UPDATE [Base].[User] SET [Code] = @p0, [Name] = @p1
OUTPUT 1
WHERE [UserId] = @p2;

相关问题