c# - ASP.NET Web API OData-将DTO查询转换为实体查询

我们目前正在调查Web API中OData查询语法的使用。
我们不打算实现完整的OData实现-仅利用查询语法。

通常,将您的应用程序划分为多个层是一种好的应用程序体系结构。
在现代Web应用程序中,这些层将包括数据层和UI/传输层,当将其发送给客户时,它们可能会以不同的方式对存储在数据库中的信息进行建模。

例如:您可能具有一个如下所示的数据库( Entity Framework )模型:

public class Employee
{
    public Guid Id {get; set;}
    public string Name {get; set;}
    public int AccessLevel {get; set;}
}

但是您的Web API可能会以其他有线格式向您的客户公开此数据:
public class EmployeeDto
{
    public string Name {get; set;}
    public string SecurityClearence {get; set;}
}

使用ASP.NET Web API和(大概?)Microsoft ASP.NET Web API OData库,我们将如何实现一种方案,使我们的客户针对DTO格式编写查询
例如:
?$filter=(SecurityClearence eq 'TopSecret')

...,然后我们将其转换为我们的数据格式。
例如:
?filter=(AccessLevel eq 007)

或其他允许我动态查询数据库的格式,例如表达式。
例如:
db.Employees.Where(translatedExpression);

我已经想到了几种手动实现此目标的方法,但是我很想知道其他人将如何解决此问题,因为我认为到目前为止,我的实现还很粗糙并且不太可能接受审查。

Web API OData库(和相关的EDM库)是否具有可以为我实现部分或全部功能的功能?

最佳答案

加文

我知道我参加这个聚会可能为时已晚,但是这是我在这件事上的两分钱。

早在2013年,我就在一个项目中工作,并提出了同样的方案。我有一个实体模型,还有一个DTO模型,可以在服务层中进出。我进行了研究,但没有找到任何库可以允许我执行以下操作:1.以自动方式从实体模型映射到DTO模型,并且2.将DTO上的过滤和排序表达式转换为实体模型。

最后,我决定编写自己的“投影”框架。几个月前,我在GitHub上发布了代码,并上载了NuGet软件包,以防有人需要执行类似操作。

现在,如果您决定尝试使用它,则必须构建和配置ProjectionsModel(类似于配置EF代码优先数据模型的方式),并指定DTO模型类如何映射到实体模型。

using ExpressionFramework.Projections;

namespace TestDTO
{
    public class MyProjectionModel : ProjectionModel
    {
        protected override void OnModelCreating(ProjectionModelBuilder modelBuilder)
        {
            modelBuilder
                .Projection<UserAccountDTO>()
                .ForSource<UserAccountEntity>(configuration => 
                {
                    configuration.Property(dto => dto.RoleCount).ExtractFrom(entity => entity.Roles.Count());
                });
        }
    }
}

然后,您可以创建一个模型并将其用于将DTO查询投影并过滤到实体查询中:
IQueryable<UserAccountEntity> usersQuery = usersList.AsQueryable();

var myProjectionModel = new MyProjectionModel();
var dtoUsersList = myProjectionModel.Project<UserAccountDTO, UserAccountEntity>(usersQuery).ToList();

即使严格过滤也不是示例的一部分,您也可以创建 QueryFilterQuerySorter对象的集合,并将它们作为参数发送到 Project方法。

如果您想进一步了解此库,请告诉我。