当我们使用customdto中的EF核心中使用ODATA和映射时。 OdataqueryOptions被覆盖

发布于 2025-02-01 15:08:46 字数 4299 浏览 5 评论 0原文

我们想做的是,在所有情况下,隶属于承运人的房客并非出现。

我的.NET核心项目中有ODATA和MAPTER。我想使用projectTotype将ODATA查询转换为DTO,我也将其用于mapster。但是,ProjectTotype正在覆盖ODATA查询生成的EF核心查询。它带有大SQL查询到数据库。它试图处理内存中的所有交易,但我只想从数据库中获取一个属性。我分享了我的项目的详细信息以及下面我期望的结果。

控制器:

[Area("odata")]
[Route("[area]/v{v:apiVersion}/[controller]")]
public class CargoCarriersODataController : ODataControllerBase
{
    private readonly IGenericReadRepository<Guid> _genericReadRepository;

    public CargoCarriersODataController(IGenericReadRepository<Guid> genericReadRepository)
    {
        _genericReadRepository = genericReadRepository;
    }

    [HttpGet]
    [EnableQuery]
    [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IQueryable<CargoCarriersODataDto>))]
    public async Task<ActionResult<IQueryable<CargoCarriersODataDto>>> Get(ODataQueryOptions<Carrier> opts)
    {
        var carriers = _genericReadRepository.GetAll<Carrier>();
        opts.ApplyTo(carriers);
        return Ok(carriers.ProjectToType<CargoCarriersODataDto>());
    }
}

DTO类:

public class CargoCarriersODataDto
{
    public int RId { get; set; }
    public Guid TenantId { get; set; }
    public TenantDto Tenant { get; set; }
    public Guid CargoCarrierId { get; set; }
    public string Name { get; set; }
    public string EnabledLogoUrl { get; set; }
    public string DisabledLogoUrl { get; set; }
    public bool IsEnabled { get; set; }
    public bool DoesSupportSameDayShipment { get; set; }
}

public class TenantDto
{
    public int RId { get; set; }
    public string Name { get; set; }
    public string CompanyName { get; set; }
    public string PhoneNumber { get; set; }
    public string CompanyEmail { get; set; }
}

public class CargoCarriersDtoCustomMap : IRegister
{
    public void Register(TypeAdapterConfig config)
    {
        config.ForType<Carrier, CargoCarriersODataDto>()
            .Map(dest => dest.RId, src => src.RId)
            .Map(dest => dest.TenantId, src => src.TenantId)
            .Map(dest => dest.CargoCarrierId, src => src.CargoCarrierId)
            .Map(dest => dest.Name, src => src.Name)
            .Map(dest => dest.EnabledLogoUrl, src => src.EnabledLogoUrl)
            .Map(dest => dest.DisabledLogoUrl, src => src.DisabledLogoUrl)
            .Map(dest => dest.IsEnabled, src => src.IsEnabled)
            .Map(dest => dest.DoesSupportSameDayShipment, src => src.DoesSupportSameDayShipment)
            .Map(dest => dest.Tenant, src => src.Tenant);
    }
}

public class TenantDtoCustomMap : IRegister
{
    public void Register(TypeAdapterConfig config)
    {
        config.ForType<Tenant, TenantDto>()
        .Ignore(dest => dest, src => new TenantDto
        {
            RId = src.RId,
            CompanyEmail = src.CompanyEmail,
            Name = src.Name,
            CompanyName = src.CompanyName,
            PhoneNumber = src.PhoneNumber
        });
    }
}

我们期望将其发送为时的查询,

http://localhost:8076/odata/v1/CargoCarriersOData?$select=name
SELECT N'Name' AS [Name], [c].[Name] AS [Value], N'Id' AS [Name], [c].[Id] AS [Value]
FROM [Carriers] AS [c]
WHERE [c].[DeletedAt] IS NULL AND ([c].[TenantId] = 'fa9f75b5-c518-40af-8731-020815551704')

但是ODATA生成的查询

SELECT [c].[RId], [c].[TenantId], CAST(0 AS bit), [t0].[RId], [t0].[Name], [t0].[CompanyName], [t0].[PhoneNumber], [t0].[CompanyEmail], [c].[CargoCarrierId], [c].[Name], [c].[EnabledLogoUrl], [c].[DisabledLogoUrl], [c].[IsEnabled], [c].[DoesSupportSameDayShipment]
FROM [Carriers] AS [c]
INNER JOIN (
SELECT [t].[Id], [t].[CompanyEmail], [t].[CompanyName], [t].[CreatedAt], [t].[CreatedBy], [t].[DeletedAt], [t].[DeletedBy], [t].[Name], [t].[PhoneNumber], [t].[RId], [t].[StorageAccountConnectionString], [t].[UpdatedAt], [t].[UpdatedBy], [t].[Version]
FROM [Tenants] AS [t]
WHERE [t].[DeletedAt] IS NULL
) AS [t0] ON [c].[TenantId] = [t0].[Id]
WHERE [c].[DeletedAt] IS NULL AND ([c].[TenantId] = 'fa9f75b5-c518-40af-8731-020815551704')

我正在使用

  • .NET CORE 3.1
  • ODATA 7.5.7
  • MAPTER 4.1.1

What we want to do is that the tenant attached to the carrier does not come under all circumstances.

I have OData and Mapster in my .NET Core project. I want to convert the OData query to dto with ProjectToType, which I also use in mapster. However, ProjectToType is overriding the EF Core query generated by the OData query. And it goes to the database with a big SQL query. It tries to handle all transactions in in-memory, but I only want to get one property from the database. I have shared the details of my project and the results I expected below.

Controller:

[Area("odata")]
[Route("[area]/v{v:apiVersion}/[controller]")]
public class CargoCarriersODataController : ODataControllerBase
{
    private readonly IGenericReadRepository<Guid> _genericReadRepository;

    public CargoCarriersODataController(IGenericReadRepository<Guid> genericReadRepository)
    {
        _genericReadRepository = genericReadRepository;
    }

    [HttpGet]
    [EnableQuery]
    [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IQueryable<CargoCarriersODataDto>))]
    public async Task<ActionResult<IQueryable<CargoCarriersODataDto>>> Get(ODataQueryOptions<Carrier> opts)
    {
        var carriers = _genericReadRepository.GetAll<Carrier>();
        opts.ApplyTo(carriers);
        return Ok(carriers.ProjectToType<CargoCarriersODataDto>());
    }
}

DTO classes:

public class CargoCarriersODataDto
{
    public int RId { get; set; }
    public Guid TenantId { get; set; }
    public TenantDto Tenant { get; set; }
    public Guid CargoCarrierId { get; set; }
    public string Name { get; set; }
    public string EnabledLogoUrl { get; set; }
    public string DisabledLogoUrl { get; set; }
    public bool IsEnabled { get; set; }
    public bool DoesSupportSameDayShipment { get; set; }
}

public class TenantDto
{
    public int RId { get; set; }
    public string Name { get; set; }
    public string CompanyName { get; set; }
    public string PhoneNumber { get; set; }
    public string CompanyEmail { get; set; }
}

public class CargoCarriersDtoCustomMap : IRegister
{
    public void Register(TypeAdapterConfig config)
    {
        config.ForType<Carrier, CargoCarriersODataDto>()
            .Map(dest => dest.RId, src => src.RId)
            .Map(dest => dest.TenantId, src => src.TenantId)
            .Map(dest => dest.CargoCarrierId, src => src.CargoCarrierId)
            .Map(dest => dest.Name, src => src.Name)
            .Map(dest => dest.EnabledLogoUrl, src => src.EnabledLogoUrl)
            .Map(dest => dest.DisabledLogoUrl, src => src.DisabledLogoUrl)
            .Map(dest => dest.IsEnabled, src => src.IsEnabled)
            .Map(dest => dest.DoesSupportSameDayShipment, src => src.DoesSupportSameDayShipment)
            .Map(dest => dest.Tenant, src => src.Tenant);
    }
}

public class TenantDtoCustomMap : IRegister
{
    public void Register(TypeAdapterConfig config)
    {
        config.ForType<Tenant, TenantDto>()
        .Ignore(dest => dest, src => new TenantDto
        {
            RId = src.RId,
            CompanyEmail = src.CompanyEmail,
            Name = src.Name,
            CompanyName = src.CompanyName,
            PhoneNumber = src.PhoneNumber
        });
    }
}

The query we expect when we send it as

http://localhost:8076/odata/v1/CargoCarriersOData?$select=name
SELECT N'Name' AS [Name], [c].[Name] AS [Value], N'Id' AS [Name], [c].[Id] AS [Value]
FROM [Carriers] AS [c]
WHERE [c].[DeletedAt] IS NULL AND ([c].[TenantId] = 'fa9f75b5-c518-40af-8731-020815551704')

but the query generated by OData

SELECT [c].[RId], [c].[TenantId], CAST(0 AS bit), [t0].[RId], [t0].[Name], [t0].[CompanyName], [t0].[PhoneNumber], [t0].[CompanyEmail], [c].[CargoCarrierId], [c].[Name], [c].[EnabledLogoUrl], [c].[DisabledLogoUrl], [c].[IsEnabled], [c].[DoesSupportSameDayShipment]
FROM [Carriers] AS [c]
INNER JOIN (
SELECT [t].[Id], [t].[CompanyEmail], [t].[CompanyName], [t].[CreatedAt], [t].[CreatedBy], [t].[DeletedAt], [t].[DeletedBy], [t].[Name], [t].[PhoneNumber], [t].[RId], [t].[StorageAccountConnectionString], [t].[UpdatedAt], [t].[UpdatedBy], [t].[Version]
FROM [Tenants] AS [t]
WHERE [t].[DeletedAt] IS NULL
) AS [t0] ON [c].[TenantId] = [t0].[Id]
WHERE [c].[DeletedAt] IS NULL AND ([c].[TenantId] = 'fa9f75b5-c518-40af-8731-020815551704')

I am using

  • .NET Core 3.1
  • OData 7.5.7
  • Mapster 4.1.1

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

林空鹿饮溪 2025-02-08 15:08:46

我看到了两个问题:

  1. opts.applyto(..) reutrns iqueryable,但是您的代码忽略了结果
  2. 应用于应用于iqueryable&lt; carrier&lt; carrier&gt ;,但应应用于iqueryable&lt; cargocarriersodatto&gt;
[HttpGet]
[EnableQuery]
[ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IQueryable<CargoCarriersODataDto>))]
public async Task<ActionResult<IQueryable<CargoCarriersODataDto>>> Get(ODataQueryOptions<Carrier> opts)
{
    var carriers = _genericReadRepository.GetAll<Carrier>();
    var projected = carriers.ProjectToType<CargoCarriersODataDto>();
    projected = opts.ApplyTo(projected);
    return Ok(projected);
}

I see two problems:

  1. opts.ApplyTo(..) reutrns IQueryable, but your code ignores result
  2. ApplyTo applied to IQueryable<Carrier> but should be applied to IQueryable<CargoCarriersODataDto>
[HttpGet]
[EnableQuery]
[ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IQueryable<CargoCarriersODataDto>))]
public async Task<ActionResult<IQueryable<CargoCarriersODataDto>>> Get(ODataQueryOptions<Carrier> opts)
{
    var carriers = _genericReadRepository.GetAll<Carrier>();
    var projected = carriers.ProjectToType<CargoCarriersODataDto>();
    projected = opts.ApplyTo(projected);
    return Ok(projected);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文