如何将一个基于DTO的OData查询映射到EF实体?

8
我在Asp.Net Web Api应用程序中有一个ODataController,它允许OData查询。我只允许读取操作,不允许更新操作。为了不直接暴露数据模型,我创建了一组DTOs。DTOs上的属性名称不一定与EF模型上的属性名称匹配。这会导致当我尝试使用OData查询EF模型时出现问题。我查看了StackOverflow上关于此主题的其他帖子,但似乎没有解决此问题的方法。
以下是我目前拥有的内容:
public IQueryable<Customer> GetCustomer(ODataQueryOptions<Customer> query)
{
        ODataModelBuilder builder = new ODataConventionModelBuilder();
        builder.EntitySet<Customer>("Customers");
        builder.EntitySet<RECORD>("Records");
        builder.Namespace = "MyDataService.Models";

        var opts = new ODataQueryOptions<RECORD>(new ODataQueryContext(builder.GetEdmModel(), typeof(RECORD)), this.ActionContext.Request);
        var records = (IQueryable<RECORD>)opts.ApplyTo(db.RECORDS);
        return ConvertToCustomerList(records);
}

这在我引用select或filter中的特定字段之前是有效的。一旦我在我的OData查询中引用字段,我就会得到一个ODataException错误,如 - Could not find a property named 'LastName' on type 'MyDataService.Models.RECORD。这是因为EF属性具有不同的命名约定。在此情况下,应使用“LAST_NAME”。
似乎我需要解析查询,然后使用正确的名称替换字段引用。我发现ODataUriParser似乎可以帮助解决这个问题,但它不如我希望的那样干净。
有人能给我提供一些解决此问题的指针吗?是否有更好的方法?
1个回答

7

WebApi OData的新功能“模型别名”可以解决您的问题。您不需要在Edm模型和DTO之间使用相同的名称。例如,有一个属性名称为OrderDto.Total,但在Edm模型中它变成了Order.Check。

        ODataModelBuilder builder = new ODataConventionModelBuilder();
        builder.ModelAliasingEnabled = true;

        EntitySetConfiguration<CustomerDto> customers = builder.EntitySet<CustomerDto>("Customers");
        EntitySetConfiguration<OrderDto> orders = builder.EntitySet<OrderDto>("Orders");
        orders.EntityType.Name = "Order";
        orders.EntityType.Property(p => p.Total).Name = "Check";
        return builder.GetEdmModel();

请参考https://aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/OData/v4/中的ODataModelAliasingSample示例。

谢谢。这非常有帮助。目前只有预发布版本,但看起来很有前途。此外,您可以在模型上使用DataContract和DataMember属性来定义别名。 - BenR
2
此外,我认为ModelAliasingEnabled属性在最新版本中已被弃用,但别名仍然有效。 - BenR
这种别名是否也可以在ApiController内实现OData查询时使用? - user5326354
我想通过OData同时公开CustomerCustomerDto。在我的控制器中,当查询GetAll时,我希望返回DTOs,而当查询单个对象时,返回Customer - Shimmy Weitzhandler
@ShimmyWeitzhandler,你应该把你的评论发表成问题,你知道这点;在你的评论中,你发布了一个链接到你的问题,以吸引关注。使用别名功能是一个永久性的替换,不会帮助你的情况。使用自定义函数代替。 - Chris Schaller
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接