Domanda

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

È stato utile?

Soluzione

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.

Altri suggerimenti

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top