问题
ContentType
--> EF model
ContentTypes
--> DTO
In my OData controller:
public Task<IQueryable<ContentTypes>> Get(ODataQueryOptions<ContentTypes> options)
{
var result = options.ApplyTo(_repository.Query().Get()
.Where(u => u.UserId == userId)
.OrderBy(o => o.Description))
.Cast<ContentTypes>();
return result;
}
I get an error 500 when trying to apply the ODataQueryOptions
. Since the class already inherits ODataController
do I even need to do theoptions.ApplyTo(...)
?
回答1:
The solution for this was to ensure the return type is the the DTO's type, and that the ODataQueryOptions
are applied to the EF entity. I then use Automapper to map the result to the DTO.
I have updated the answer based on @Schandlich 's suggestions, however some issues persist:
[Queryable]
public virtual IHttpActionResult Get(ODataQueryOptions<ContentType> options)
{
var userId = 102; // mock
try
{
var results = options.ApplyTo(_uow.Repository<ContentType>()
.Query()
.Get()
.Include(u => u.User)
.Where(u => u.UserId == userId)
.OrderBy(o => o.Description)).Cast<ContentType>()
.Select(x => new ContentTypeDTO()
{
//projection goes here
ContentTypeId = x.ContentTypeId,
Description = x.Description,
UserDTO = new UserDTO
{
UserId = x.UserId,
UserName = x.User.UserName
}
});
return this.Ok(results);
}
catch (Exception ex)
{
throw ex;
}
}
The reason for using ODataQueryOptions
is that I want EF to handle the filtering down at the database call level. Otherwise, I would get all records returned, then the Queryable
would kick in to return, say the first page of results.
I removed the Automapper code, but curious as to why not use this?
As @Schandlich pointed out, however, this will not work for $select
or $expand
.
回答2:
Updated based on @ElHaix's answer. I cannot recommend more strongly against using AutoMapper to map from a data source like this. This is also assuming that the query applied to the repository is being applied before the call the database.
[Queryable]
public virtual IHttpResult Get()
{
var userId = 102; // mock
try
{
var results = _uow.Repository<ContentType>()
.Query()
.Get()
.Where(u => u.UserId == userId)
.OrderBy(o => o.Description)
.Select(x => new ContentTypeDTO()
{
//projection goes here
});
return this.Ok(results);
}
catch (Exception ex)
{
throw ex;
}
}
Also, I would try doing a $select against ElHaix's answer.
回答3:
I was able to achieve this with AutoMapper Project() extension. $select, $filter, etc were all applied to database query.
[TestMethod]
public void DataShaping_With_AutoMapper_And_OData_Select_Test()
{
OracleMonitor myMonitor = new OracleMonitor();
myMonitor.IsActive = true;
var dbcontext = new MyDbContext();
var datasource = dbcontext.Datasouces;
Assert.IsNotNull(datasource);
SetupAutoMapper();
var odataQuery = Extensions.CreateDummyODataQuery<DataSourceDTO>("$expand=Fields($select=Description)&$select=Name");
var withShaping = datasource.Project().To<DataSourceDTO>();
Assert.IsNotNull(withShaping);
var withODataQuery = odataQuery.ApplyTo(withShaping);
Assert.IsNotNull(withODataQuery);
string strJson = JsonConvert.SerializeObject(withODataQuery);
Assert.IsFalse(String.IsNullOrEmpty(strJson));
}
来源:https://stackoverflow.com/questions/21647830/is-it-possible-to-use-odataqueryoptions-with-dtos