如何将针对 DTO 的 OData 查询映射到另一个实体? [英] How do I map an OData query against a DTO to another entity?

查看:25
本文介绍了如何将针对 DTO 的 OData 查询映射到另一个实体?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题与此非常相似:如何将针对 DTO 的 OData 查询映射到 EF 实体?我有一个简单的设置来测试 ASP.NET Web API OData V4 $filter 功能.我想要做的是别名"ProductDTO 的某些属性以匹配 Product 实体的属性.例如,用户将使用以下请求调用 ProductsController:

My question is very similar to this one: How do I map an OData query against a DTO to an EF entity? I have a simple setup to test the ASP.NET Web API OData V4 $filter functionality. What I would like to do is to "alias" some properties of the ProductDTO to match the properties of Product entity. The user will call the ProductsController for example with the following request:

GET products?$filter=DisplayName eq ‘test’

GET products?$filter=DisplayName eq ‘test’

产品类:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Level { get; set; }
    public Product()
    { }
}

ProductDTO 类:

The ProductDTO class:

public class ProductDTO
{
    public int Id { get; set; }
    public string DisplayName { get; set; }
    public int DisplayLevel { get; set; }
    public ProductDTO(Product product)
    {
        this.DisplayName = product.Name;
        this.DisplayLevel = product.Level;
    }
}

产品控制器:

public class ProductsController : ApiController
{
    public IEnumerable<ProductDTO> Get(ODataQueryOptions<Product> q)
    {
        IQueryable<Product> products = this._products.AsQueryable();
        if (q.Filter != null) products = q.Filter.ApplyTo(this._products.AsQueryable(), new ODataQuerySettings()) as IQueryable<Product>;
        return products.Select(p => new ProductDTO(p));
    }
}

当然,我遇到了以下异常:

Of course I’m getting the following exception:

在类型TestAPI.Models.Product"上找不到名为DisplayName"的属性

Could not find a property named 'DisplayName' on type 'TestAPI.Models.Product'

我尝试通过将以下几行添加到 WebApiConfig.cs 来使用新引入的别名功能

I tried to use the newly introduced aliasing feature by adding the following lines to the WebApiConfig.cs

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        …
        IEdmModel model = GetModel();
        config.MapODataServiceRoute("*", "*", model);
    }

    private static IEdmModel GetModel()
    {
        ODataModelBuilder builder = new ODataConventionModelBuilder();
        EntitySetConfiguration<Product> products = builder.EntitySet<Product>("Product");
        products.EntityType.Property(p => p.Name).Name = "DisplayName";
        products.EntityType.Property(p => p.Level).Name = "DisplayLevel";
        return builder.GetEdmModel();
    }
}

我想我错误地使用了别名功能,因为抛出了与上述相同的异常.如果我调用以下请求,它会起作用,但这不是我想要实现的:

I suppose that I'm using the aliasing feature incorrectly, because the same exception as described above is thrown. If I invoke the following request it works, but this is not what I'm trying to achieve:

GET products?$filter=Name eq ‘test’

GET products?$filter=Name eq ‘test’

更新:

我同意 gdoron,Get 端点应如下所示:

I agree with gdoron, the Get endpoint should look like this:

public IEnumerable<ProductDTO> Get(ODataQueryOptions<ProductDTO> q)

但这应该可以在没有 AutoMapper 的情况下解决吗?

But this should be solvable without AutoMapper?

推荐答案

我找到了一个不使用 AutoMapper 的解决方案.

I found a solution without using AutoMapper.

ProductsController 现在看起来像这样:

The ProductsController now looks like this:

public class ProductsController : ApiController
{
    public IEnumerable<ProductDTO> Get(ODataQueryOptions<ProductDTO> q)
    {
        IQueryable<Product> products = this._products.AsQueryable();

        IEdmModel model = GetModel();
        IEdmType type = model.FindDeclaredType("TestAPI.Models.Product");
        IEdmNavigationSource source = model.FindDeclaredEntitySet("Products");
        ODataQueryOptionParser parser = new ODataQueryOptionParser(model, type, source, new Dictionary<string, string> { { "$filter", q.Filter.RawValue } });
        ODataQueryContext context = new ODataQueryContext(model, typeof(Product), q.Context.Path);
        FilterQueryOption filter = new FilterQueryOption(q.Filter.RawValue, context, parser);

        if (filter != null) products = filter.ApplyTo(products, new ODataQuerySettings()) as IQueryable<Product>;
        return products.Select(p => new ProductDTO(p));
    }
}

WebApiConfig:

The WebApiConfig:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        …
        IEdmModel model = GetModel();
        config.MapODataServiceRoute("*", "*", model);
    }

    private static IEdmModel GetModel()
    {
        ODataModelBuilder builder = new ODataConventionModelBuilder();
        EntitySetConfiguration<Product> product = builder.EntitySet<Product>("Products");
        product.EntityType.Name = "Product";
        product.EntityType.Namespace = "TestAPI.Models";
        product.EntityType.Property(p => p.Name).Name = "DisplayName";
        product.EntityType.Property(p => p.Level).Name = "DisplayLevel";
        return builder.GetEdmModel();
    }
}

这篇关于如何将针对 DTO 的 OData 查询映射到另一个实体?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆