Я создаю обобщенный c asyn c метод обновления для Entity Framework 6.x on. NET Framework 4.8. Вот класс:
public class GenericUpdate<TEntity, TId, TDto>
where TEntity : class
where TId : IConvertible
where TDto : class
{
public async Task UpdateSingleAsync(string searchPropertyName, TId searchPropertyValue, TDto dto)
{
try
{
var tableType = typeof(TEntity);
// https://stackoverflow.com/questions/30029230/dynamic-lambda-expression-for-singleordefault
var param = Expression.Parameter(tableType, "m");
var searchProperty = Expression.PropertyOrField(param, searchPropertyName);
var constSearchValue = Expression.Constant(searchPropertyValue);
var body = Expression.Equal(searchProperty, constSearchValue);
var lambda = Expression.Lambda(body, param);
using (var context = new MyContext())
{
var dbTable = context.Set(tableType);
var genericSingleOrDefaultAsyncMethod =
typeof(QueryableExtensions).GetMethods().First(m => m.Name == "SingleOrDefaultAsync" && m.GetParameters().Length == 2);
var specificSingleOrDefaultAsync = genericSingleOrDefaultAsyncMethod.MakeGenericMethod(tableType);
// https://stackoverflow.com/a/16153317/177416
var result = (Task<TEntity>) specificSingleOrDefault.Invoke(null, new object[] { dbTable, lambda });
await result;
context.Entry(result).CurrentValues.SetValues(dto);
await context.SaveChangesAsync();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
throw;
}
}
}
На result
он взрывается с:
System.ArgumentException: объект типа 'System.Linq.Expressions.Expression [System .Func [MyEntities.Models.SomeEntity, System.Boolean]] 'нельзя преобразовать в тип' System.Threading.CancellationToken '.
Как вы вызываете Invoke
в асинхронном режиме c метод? Что я делаю неправильно?
Обновление 1: Я использовал этот ответ , чтобы добавить (Задачу) в мой код, но, очевидно, я делаю что-то не так.
Обновление 2: После @StephenCleary внесены следующие изменения:
dynamic dbTable = context.Set(tableType);
var result = await QueryableExtensions.SingleOrDefaultAsync(dbTable, lambda);
Первое предложение не сработало, поскольку dbTable
не имело SingleOrDefaultAsync
.
Теперь получаем эту ошибку:
Наилучший перегруженный метод соответствует «System.Data.Entity.QueryableExtensions.SingleOrDefaultAsyn c (System.Linq.IQueryable, System.Threading.CancellationToken)» неверные аргументы
Обновление 3 и решение: Благодаря @StephenCleary это решение работает как чудо:
dynamic lambda = Expression.Lambda(body, param);
using (var context = new MyContext())
{
dynamic dbTable = context.Set(tableType);
var result = await QueryableExtensions.SingleOrDefaultAsync(dbTable, lambda);
if(result != null)
{
context.Entry(result).CurrentValues.SetValues(dto);
await context.SaveChangesAsync();
}
}