سؤال

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(...)?

هل كانت مفيدة؟

المحلول

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.

نصائح أخرى

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.

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));
        }

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top