Не удается применить $select при использовании ODataQueryOptions

#c# #asp.net-core #entity-framework-core #odata

#c# #asp.net-ядро #сущность-фреймворк-ядро #odata

Вопрос:

Я пытаюсь реализовать запросы к Sql Server через EF Core и OData(7.1.0).

Метод действия выглядит следующим образом:

 [HttpGet]
public IEnumerable<UserInfoDto> Get(ODataQueryOptions ops)
{
     return this.service.GetUserInfos(ops);
}
  

Сервисный код:

 public List<UserInfoDto> GetUserInfos(ODataQueryOptions ops)
{
    using (var context = new EFContext())
    {
        var query = context.Users.Join(context.Customers, x => x.CustomerId, y => y.Id, (x, y) => new UserInfoDto
        {
            Id = x.Id,
            Name = x.Name,
            Age = x.Age,
            CustomerId = x.CustomerId,
            CustomerTitle = y.Title,
            CustomerDescription = y.Description
        });

        var result = ops.ApplyTo(query).Cast<UserInfoDto>().ToList();
        return resu<
    }
}
  

Configute Метод запуска:

 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
     app.UseMvc(b => 
     {
         b.Count().Filter().OrderBy().Select().MaxTop(null);
         b.EnableDependencyInjection();
     });
}
  

Однако, когда у меня возникает $select запрос (например https://localhost:5001/api/userinfos ?$select=id), вместо прогнозируемого результата я получаю сообщение об ошибке:

Исключение InvalidOperationException: оператор принуждения не определен между типами ‘Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder SelectSome`1[Oda taApp.UserInfoDto]’ и ‘OdataApp.UserInfoDto’.

Чего мне не хватает? Любая помощь приветствуется.

Ответ №1:

Когда вы используете $select опцию запроса для OData, вам нужен IQueryable of dynamic .

Например, представьте следующий класс:

 public class Person {
    public int Id { get; set }
    public string Name { get; set; }
}

  

Итак, если у вас есть запрос без $select , IQueryable сгенерирует коллекцию Person со всеми свойствами (id и name) в каждом элементе.

Но, если вы используете $select=id запрос, каждый элемент будет иметь только свойство ID, и вы не сможете привести динамический тип к типу Person .

Другими словами, вы не можете использовать $select и возвращать a List<UserInfoDto> , вам нужно вернуть a List<dynamic> без метода приведения, вот так:

     var result = ops.ApplyTo(query) as IQueryable<dynamic>;
    return result.ToList();
  

Редактировать:

полная реализация метода будет:

 // changing the return type
public List<dynamic> GetUserInfos(ODataQueryOptions<UserInfoDto> ops)
{
    using (var context = new EFContext())
    {
        var query = context.Users.Include(Customers, x => x.CustomerId, y => y.Id, (x, y) => new UserInfoDto
        {
            Id = x.Id,
            Name = x.Name,
            Age = x.Age,
            CustomerId = x.CustomerId,
            CustomerTitle = y.Title,
            CustomerDescription = y.Description
        });
        // casting the applyto result
        var result = ops.ApplyTo(query) as IQueryable<dynamic>;
        return result.ToList();
    }
}
  

Комментарии:

1. Спасибо, я попробую и сообщу, работает ли это для меня c:

2. Да, после вашего объяснения все становится для меня вполне логичным! Поскольку OData $select не охватывает пару сложных запросов, которые мне нужны, я думаю, я останусь со статическим DTO и $select вообще запрещу операции. В любом случае, большое спасибо за вашу помощь!

3. Объект типа ‘System.Linq. Перечисляемый 1[System.Object]' cannot be converted to type 'System.Linq.IQueryable запрос 1[DtoExample]

4. @Jackie у тебя есть способ обойти это

5. @rodrigo проблема / ошибка, опубликованная Джеки, заключается в том, что после удаления приведения $select по-прежнему не работает