#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 по-прежнему не работает