Как правильно составить linq запрос из бд?
Пытаюсь правильно составить запрос.
Запрос должен группировать по ApplicationUserId. А дальше получить первый объект и вернуть вместе с пользователем.
(from trainings in dbContext.TrainingObjects
group trainings by trainings.ApplicationUserId into groups
let bTr = groups.OrderByDescending(a => a.Index).First()
let user = dbContext.Users.First(a => a.Id == groups.Key)
select new
{
tr = bTr,
user = user
}).ToList()
Но вылазит ошибка:
System.InvalidOperationException: 'Processing of the LINQ expression '(GroupByShaperExpression: KeySelector: (t.ApplicationUserId), ElementSelector:(EntityShaperExpression: EntityType: TrainingObject ValueBufferExpression: (ProjectionBindingExpression: EmptyProjectionMember) IsNullable: False ) )'
public class TrainingObject
{
[Key]
public string Id { get; set; }
[Required]
public string ApplicationUserId { get; set; }
[JsonIgnore, IgnoreDataMember, ForeignKey("ApplicationUserId")]
public UserDetails UserDetails { get; set; }
public double Index { get; set; }
...
}
public class UserDetails
{
[Key]
public string Id { get; set; }
public string ApplicationUserId { get; set; }
[ForeignKey("ApplicationUserId")]
public ApplicationUser ApplicationUser { get; set; }
public ICollection<TrainingObject> TrainingObjects { get; set; }
...
}
Попробовал в один запрос, но не дает сделать упорядочивание
(from trs in dbContext.TrainingObjects
join user in dbContext.UsersDetails on trs.ApplicationUserId equals user.Id
group trs by trs.ApplicationUserId into grTrs
select new
{
trs = grTrs.OrderByDescending(q=>q.Index).First(),
user = grTrs.First().UserDetails
}).ToList();
OrderByDescending(q => q.Index)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either
Ответы (1 шт):
Для LINQ to Entities, существует пока нерушимое ограничение - после group by можно доставать только ключ группировки или результат агрегации. В вашем же случае вы хотите получить целый объект.
Это обусловлено ограничением самого SQL. Если вам нужен такой запрос, необходимо использовать чистый SQL и оконные функции. Оконные функции не поддерживаются реализацией EF любых версий.
Но, на всякий случай, оставлю вариант с использованием расширения для EF Core https://github.com/linq2db/linq2db.EntityFrameworkCore - используйте версию 3.X
Расширение использует транслятор LINQ от linq2db и не имеет ограничений присущих EF Core. Заранее предупреждаю, я создатель этого расширения.
var rnQuery =
from t in dbContext.TrainingObjects
select new
{
RN = Sql.Ext.RowNumber().Over()
.PartitionBy(t.ApplicationUserId)
.OrderByDesc(t.Index)
.ToValue(),
tr = t,
user = t.UserDetails.ApplicationUser
};
var resultQuery =
from q in rnQuery
where q.RN == 1
select new
{
q.tr,
q.user
};
var result = resultQuery
.ToLinqToDB()
.ToList();