我有Project实体和ProjectDTO。 我正在尝试创建一个WebAPI控制器方法,该方法可以获取并返回ProjectDTO并使其支持OData。
问题是我正在使用可以使用Project实体而不是Project DTO查询数据库的ORM。有没有办法可以根据ProjectDTO从OData应用过滤/排序/分页到项目实体查询?
public ODataQueryResult<ProjectDTO> GetProjects(ODataQueryOptions<ProjectDTO> query)
{
var context = new ORM_Context();
var projects = context.Projects; // IQueryable<Project>
var projectDtos = query.ApplyTo(projectDTOs)); // <-- I want to achieve something similar here
var projectDTOs =
projects.Select(
x =>
new ProjectDTO
{
Id = x.Id,
Name = x.Name
});
var projectsQueriedList = projectDtos.ToList();
var result = new ODataQueryResult<ProjectDTO>(projectsQueriedList, totalCount);
return result;
}
答案 0 :(得分:4)
喜欢这个(我还没试过编译)
using(var dataContext = new ORM_Context())
{
var projects = dataContext.Projects; // IQueryable<Project>
//Create a set of ODataQueryOptions for the internal class
ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<Project>("Project");
var context = new ODataQueryContext(
modelBuilder.GetEdmModel(), typeof(Project));
var newOptions = new ODataQueryOptions<Project>(context, Request);
var t = new ODataValidationSettings() { MaxTop = 25 };
var s = new ODataQuerySettings() { PageSize = 25 };
newOptions.Validate(t);
IEnumerable<Project> internalResults =
(IEnumerable<Project>)newOptions.ApplyTo(projects, s);
int skip = newOptions.Skip == null ? 0 : newOptions.Skip.Value;
int take = newOptions.Top == null ? 25 : newOptions.Top.Value;
var projectDTOs =
internalResults.Skip(skip).Take(take).Select(x =>
new ProjectDTO
{
Id = x.Id,
Name = x.Name
});
var projectsQueriedList = projectDtos.ToList();
var result = new ODataQueryResult<ProjectDTO>(
projectsQueriedList, totalCount);
return result;
}
答案 1 :(得分:2)
我认为最简单的方法是使用AutoMapper。所以,对于你的DTO
[DataContract(Name = "Products")]
public class ProductDTO
{
[Key]
[DataMember]
public string MyProductMember1 { get; set; }
[DataMember]
public string MyProductMember2 { get; set; }
...
}
你应该在AutoMapper配置中写一个地方:
Mapper.CreateMap<Product, ProductDTO>();
以及为OData构建IEdmModel的某个地方:
builder.EntitySet<ProductDTO>("Products");
并且控制器的代码看起来像
public class ProductsController : ODataController
{
[EnableQuery]
public IHttpActionResult Get()
{
var products = context.Products; // IQueryable<Product>
return Ok(products.Project().To<ProductDTO>());
}
}
这样您就不需要直接公开您的ORM实体,并且可以使用OData进行过滤,分页,计数甚至扩展嵌套集合,对于EF,它将使用表格转换为相应的SQL请求。产品已映射。但要小心:对于更复杂的情况(例如,嵌套集合),可能会导致非最佳SQL请求。
答案 2 :(得分:0)
试试这个:
public object GetProjects(ODataQueryOptions<Project> query)
{
var context = new ORM_Context();
var projects = query.ApplyTo(context.Projects);
var projectDTOs = projects.Select(
x =>
new ProjectDTO
{
Id = x.Id,
Name = x.Name
});
return new
{
TotalCount = Request.GetInlineCount(), //before paging
Results = projectDTOs.ToList()
};
}
显然,最重要的是将正确的类型传递给ODataQueryOptions&lt;&gt;然后它执行它的魔法就好了。这是因为它使用该特定类型来查询您的集合/ db上下文,因此它必须是实际存储在集合/上下文中的类型,而不是您要返回的内容。
显然,您的DTO应该与您的ORM对象非常相似(并且它们会在您的代码段中执行),或者从用户/客户的角度来看,这不会很好。
我没有尝试编译上面的代码,因为我没有你的类和其他基础设施,但它应该足以传达这个想法。