gpt4 book ai didi

c# - EF Core - 使用 Automapper 从 OData 返回映射的多对多关系

转载 作者:行者123 更新时间:2023-12-04 12:58:04 27 4
gpt4 key购买 nike

信息
应用程序类型是托管 Blazor Web 程序集。以下是我正在使用的 nuget 软件包的版本。尝试展开多对多关系的导航属性时发生错误。这些类被映射到 DTO 类,从而将中间关系类展平。

  • .Net 核心版本="3.1"
  • AutoMapper 版本="10.0.0"
  • AutoMapper.AspNetCore.OData.EFCore 版本="2.0.1"
  • AutoMapper.Extensions.ExpressionMapping 版本="4.0.1"
  • AutoMapper.Extensions.Microsoft.DependencyInjection Version="8.0.1"
  • Microsoft.AspNetCore.Components.WebAssembly.Server Version="3.2.1"
  • Microsoft.AspNetCore.OData 版本="7.5.0"

  • 要运行此存储库,您将需要 SQL Server 的免费版本或更高版本
    将 EfCoreAutomapperOdata.Server 项目设置为启动项目并导航到类(class)页面 (https://localhost:5001/courses) 并单击任一类(class)。这将引发以下错误: System.InvalidOperationException: No generic method 'Include' on type 'Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic. at System.Linq.Expressions.Expression.FindMethod(Type type, String methodName, Type[] typeArgs, Expression[] args, BindingFlags flags)...楷模
    here - Entity Modelshere - Dto Models用于类定义
    自动映射器配置
        public class AutomapperConfig : Profile
    {
    public AutomapperConfig()
    {
    CreateMap<Instructor, InstructorDto>();
    CreateMap<InstructorDto, Instructor>();

    CreateMap<Course, CourseDto>()
    .ForMember(dto => dto.Students, opt => {
    opt.MapFrom(_ => _.Students.Select(y => y.Student));
    });
    CreateMap<CourseDto, Course>()
    .ForMember(ent => ent.Students, ex => ex
    .MapFrom(x => x.Students.Select(y => new CourseStudent {
    CourseId = x.Id,
    StudentId = y.Id
    })));

    CreateMap<Student, StudentDto>()
    .ForMember(dto => dto.Courses, opt => {
    opt.MapFrom(x => x.Courses.Select(y => y.Course));
    })
    .ForMember(dto => dto.Friends, opt => {
    opt.MapFrom(x => x.Friends.Select(y => y.Friend));
    });
    CreateMap<StudentDto, Student>()
    .ForMember(ent => ent.Courses, ex => ex
    .MapFrom(x => x.Courses.Select(y => new CourseStudent
    {
    StudentId = x.Id,
    CourseId = y.Id
    })));
    }
    }
    启动
        public class Startup
    {
    public Startup(IConfiguration configuration)
    {
    Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
    // ------ Some code removed for brevity ------

    services.AddOData();
    services.AddAutoMapper(cfg => { cfg.AddExpressionMapping(); },typeof(AutomapperConfig));

    // ------ Some code removed for brevity ------
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
    // ------ Some code removed for brevity ------

    app.UseHttpsRedirection();
    app.UseBlazorFrameworkFiles();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
    endpoints.MapRazorPages();
    endpoints.MapControllers();
    endpoints.EnableDependencyInjection();
    endpoints.Select().Filter().OrderBy().Count().Expand().MaxTop(1000);
    endpoints.MapODataRoute("odata", "odata", GetEdmModel());
    endpoints.MapFallbackToFile("index.html");
    });
    }

    private IEdmModel GetEdmModel()
    {
    var builder = new ODataConventionModelBuilder();
    builder.EntitySet<CourseDto>("Courses");
    builder.EntitySet<InstructorDto>("Instructors");
    builder.EntitySet<StudentDto>("Students");

    return builder.GetEdmModel();
    }
    }
    类(class)负责人
        public class CourseController : ODataController
    {
    protected readonly BlazorContext _context;
    protected readonly IMapper _mapper;

    public CourseController(BlazorContext context, IMapper mapper)
    {
    _context = context;
    _mapper = mapper;
    }

    [HttpGet]
    [ODataRoute("Courses")]
    public async Task<IActionResult> Get(ODataQueryOptions<CourseDto> options)
    {
    return Ok(await _context.Course.GetAsync(_mapper, options));
    }

    [HttpGet]
    [ODataRoute("Courses({id})")]
    public async Task<IActionResult> Get([FromODataUri] int id, ODataQueryOptions<CourseDto> options)
    {
    return Ok((await _context.Course.GetAsync(_mapper, options)).Where(s => s.Id == id).ToList());
    }
    }
    失败的示例 odata api 查询 /odata/Courses?$expand=Students再现
    我已经为此问题构建了演示 Blazor WASM 应用程序以重现
    Repository

    最佳答案

    一般设置
    要使扩展工作,您需要允许 $expand query option要使用的。像这样显式配置它:

    private IEdmModel GetEdmModel()
    {
    var builder = new ODataConventionModelBuilder();

    builder.EntitySet<EstimateDto>(nameof(MyContext.Estimates))
    .EntityType
    .Expand(); // <-- allow expansion

    builder.EntitySet<TypeDto>(nameof(MyContext.Types))
    .EntityType
    .Expand(); // <-- allow expansion

    builder.EntitySet<SubTypeDto>(nameof(MyContext.SubTypes));

    return builder.GetEdmModel();
    }
    您还需要更新 AutoMapper 映射,以允许查询成功映射到 DTO:
    public class AutoMapperConfig : Profile
    {
    public AutoMapperConfig()
    {
    CreateMap<Estimate, EstimateDto>()
    .ForMember(
    dto => dto.Types,
    opt => opt.MapFrom(x => x.EstimateTypes.Select(y => y.Type)));

    // The following mapping is needed for expansion to work:
    CreateMap<EstimateTypeRel, TypeDto>()
    .ForMember(
    dto => dto.SubTypes,
    opt => opt.MapFrom(x => x.Type));

    CreateMap<Type, TypeDto>()
    .ForMember(
    dto => dto.SubTypes,
    opt => opt.MapFrom(x => x.SubTypes.Select(y => y.SubType)));

    CreateMap<SubTypeRel, SubTypeDto>();
    }
    }
    设置该配置后,此问题至少有两种可能的解决方案,具体取决于您的要求:
    A) 只展开 Types如果您只想扩展 Types ,您需要通过添加 .Where(z => z != null) 来更改您的 AutoMapper 映射。条款,因为正如异常告诉您的那样, null集合中不允许使用值,但 OData 将它们包含在非扩展 SubType 中实体:
    public class AutoMapperConfig : Profile
    {
    public AutoMapperConfig()
    {
    CreateMap<Estimate, EstimateDto>()
    .ForMember(
    dto => dto.Types,
    opt => opt.MapFrom(
    x => x.EstimateTypes.Select(y => y.Type)
    .Where(z => z != null))); // <-- filter out null values

    CreateMap<EstimateTypeRel, TypeDto>()
    .ForMember(
    dto => dto.SubTypes,
    opt => opt.MapFrom(x => x.Type));

    CreateMap<Type, TypeDto>()
    .ForMember(
    dto => dto.SubTypes,
    opt => opt.MapFrom(
    x => x.SubTypes.Select(y => y.SubType)
    .Where(z => z != null))); // <-- filter out null values

    CreateMap<SubTypeRel, SubTypeDto>();
    }
    }
    然后您可以使用以下查询:
    https://localhost:5001/odata/Estimates(1)?$expand=Types
    B) 也展开 SubTypes另一种方法是扩展 SubTypes属性也是如此,因此可以正确填充集合。要在多个级别上扩展 DTO 映射属性,请使用 $expand查询字符串中的查询选项,如下所示:
    https://localhost:5001/odata/Estimates(1)?$expand=Types($expand=SubTypes)

    关于c# - EF Core - 使用 Automapper 从 OData 返回映射的多对多关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63675676/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com