entity-framework-core - Automapper ProjectTo 和 JSON 列
问题描述
我在 EF Core 中有一些简单的模型(带有使用 Npgsql 的 Postgres 后端)。
public class Test : Model
{
public string Id { get; set; }
public TestInfo Info { get; set; }
public string Name { get; set; }
}
public class TestInfo
{
public string[] Tags { get; set; }
public string Name { get; set; }
public int[] Counts { get; set; }
}
public class TestDTO
{
public string[] Tags { get; set; }
public string Name { get; set; }
public string InfoName{ get; set; }
public int[] Counts { get; set; }
}
EF Core 配置和 Autommaper 配置文件是
public class TestConfig
{
public override void Configure(EntityTypeBuilder<Test> builder)
{
builder.HasKey(m => m.Id);
builder.Property(s => s.Info)
.HasConversion(
v => JsonConvert.SerializeObject(v),
v => JsonConvert.DeserializeObject<TestInfo>(v)
)
.HasColumnType("jsonb");
builder.HasIndex(s => s.Info)
.HasMethod("gin")
.HasOperators("jsonb_ops");
}
}
public class TestProfile : Profile
{
public TestProfile()
{
CreateMap<Test, TestDTO>()
.ForMember(dest => dest.InfoName, opt => opt.MapFrom(src => src.Info.Name))
.ForMember(dest => dest.Tags, opt => opt.MapFrom(src => src.Info.Tags))
.ForMember(dest => dest.Counts, opt => opt.MapFrom(src => src.Info.Counts))
.ReverseMap();
}
}
我一直在尝试使用 Automapper 的 ProjectTo 进行查询,但无法弄清楚如何使其工作。下面的控制器代码抛出强制错误
[HttpGet]
[Route("/test/{id}")]
public async Task<IActionResult> GetTest([FromRoute (Name = "id")][Required]string id)
{
var t = await _mapper.ProjectTo<TestDTO>(
_context.Tests.Where(s => s.Id == id)
)
.ToListAsync();
return Ok(t);
}
错误(从 System.String 到 System.string[] 的标签还有另一个错误,但为简洁起见,我省略了)
System.InvalidOperationException: No coercion operator is defined between types 'System.String' and 'System.Int32[]'.
at System.Linq.Expressions.Expression.GetUserDefinedCoercionOrThrow(ExpressionType coercionType, Expression expression, Type convertToType)
at System.Linq.Expressions.Expression.Convert(Expression expression, Type type, MethodInfo method)
at System.Linq.Expressions.Expression.Convert(Expression expression, Type type)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.CreateGetValueExpression(ParameterExpression dbDataReader, Int32 index, Boolean nullable, RelationalTypeMapping typeMapping, Type type, IPropertyBase property)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.VisitExtension(Expression extensionExpression)
at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at System.Linq.Expressions.ExpressionVisitor.VisitMemberAssignment(MemberAssignment node)
at System.Linq.Expressions.ExpressionVisitor.VisitMemberBinding(MemberBinding node)
at System.Linq.Expressions.ExpressionVisitor.Visit[T](ReadOnlyCollection`1 nodes, Func`2 elementVisitor)
at System.Linq.Expressions.ExpressionVisitor.VisitMemberInit(MemberInitExpression node)
at System.Linq.Expressions.MemberInitExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.ProcessShaper(Expression shaperExpression, RelationalCommandCache& relationalCommandCache, LambdaExpression& relatedDataLoaders)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.VisitShapedQuery(ShapedQueryExpression shapedQueryExpression)
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.VisitExtension(Expression extensionExpression)
at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass12_0`1.<ExecuteAsync>b__0()
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetAsyncEnumerator(CancellationToken cancellationToken)
at System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable`1.GetAsyncEnumerator()
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at dms_apis.Controllers.OrganisationController.GetTest(String id) in /home/viet/src/dms-apis/Controllers/OrganisationController.cs:line 62
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
我尝试Select
在控制器中使用手动映射,这似乎可行,但 ProjectTo 似乎要好得多
[HttpGet]
[Route("/test/{id}")]
public async Task<IActionResult> GetTest([FromRoute (Name = "id")][Required]string id)
{
var t = _context.Tests
.Select(s => new TestDTO{
Id = s.Id,
Name = s.Info.Name
})
.Where(s => s.Id == id)
.ToList();
return Ok(t);
}
在这种情况下使用 ProjectTo 的正确方法是什么?非常感谢。
解决方案
推荐阅读
- tensorflow - 进程终止后释放 GPU 内存
- ruby-on-rails - 如果在 after_create 中未调用函数,如何在 Ruby on Rails 中引发错误
- python - 从维基百科抓取链接
- vue.js - 如何在Vue.JS中将数组放入多选中
- ios - UI标签读取为零?
- javascript - 在不使用循环、内置方法或 javascript 中的 .length 属性的情况下查找字符串的长度?
- oracle - 为什么使用count时bridge sql developer命令失败
- c# - C# 异步函数投影到属性
- linux - 如何使用 Golang 安装 Gin
- javascript - Mocha - Chai Unit Terst 报告生成 - NodeJS