Я работаю над приложением с .net core 2 и Entity Framework Core 2.
У меня есть следующие модели:
Topic {
int TopicID,
List<Message> Messages,
…
}
Message {
int MessageID,
int TopicID,
Topic Topic,
int UserID,
User User,
…
}
User {
int UserID,
…
}
Я хочу получить все данные для темы и ее отношений, так что если у меня есть тема с 3 сообщениями, каждое из которых написано другим пользователем, я получу следующий объект:
var topic = new Topic() {
TopicID: 1,
Messages: new Message[] {
new Message() { MessageID: 1, TopicID: 1, UserID: 1, User: new User() { UserID: 1 } },
new Message() { MessageID: 2, TopicID: 1, UserID: 2, User: new User() { UserID: 2 } },
new Message() { MessageID: 3, TopicID: 1, UserID: 1, User: new User() { UserID: 3 } }
}
}
Это было просто, и я сделал это со следующей реализацией:
return context.Topics
.Include(t => t.Messages)
.ThenInclude(m => m.User)
.AsNoTracking()
.SingleOrDefault(t => t.TopicID == topicId);
но теперь я хочу добавить некоторые условия к сообщениям:
- принимать только 2 сообщения одновременно
- передать параметр, указывающий, что я хочу принимать только сообщения, в которых
messageID
меньше заданного параметра
Я проверил и обнаружил, что Include()
не имеет возможности использовать Take()
и Where()
, поэтому я попытался реализовать это с помощью Select()
:
return context.Topics
.Where(t => t.TopicID == topicId)
.Select(t => new {
TopicId = t.TopicID,
Messages = t.Messages
.Where(m => m.MessageID < messageId)
.Take(2)
})
.AsNoTracking()
.SingleOrDefault();
Когда я удаляю Where()
и Take()
изнутри Select()
, он работает (но без условий, которые я хочу реализовать), но если я их оставлю, он возвращает ошибки:
{System.ArgumentException: выражение типа 'System.Collections.Generic.IEnumerable 1[Microsoft.EntityFrameworkCore.Storage.ValueBuffer]' cannot be used for parameter of type 'System.Collections.Generic.IEnumerable
1 [Dal.Models.Message]' метода 'System.Collections.Generic.IEnumerable 1[Dal.Models.Message] _ToEnumerable[Message](System.Collections.Generic.IEnumerable
1 [Dal.Models. Сообщение]) 'Имя параметра: arg0 в System.Dynamic.Utils.ExpressionUtils.ValidateOneArgument (метод MethodBase, ExpressionType nodeKind, аргументы выражения, ParameterInfo pi, String methodParamName, String аргументParamName, индекс Int32) в System.Linq.Expressions.Expression.Call. (Метод MethodInfo, Выражение arg0) в Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.ProjectionExpressionVisitor.VisitSubQuery (выражение SubQueryExpression) в Remotion.Linq.Clauses.Expressions.SubQueryExpression.Accept (выражение). Выражение .Visitor. Узел выражения) в Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.RelationalProjectionExpressionVisitor.Visit (выражение выражения) в System.Linq.Expressions.ExpressionVisitor.VisitAndConvert [T] (Rea Регистратор dOnlyCollection 1 nodes, String callerName) at Remotion.Linq.Parsing.RelinqExpressionVisitor.VisitNew(NewExpression expression) at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.RelationalProjectionExpressionVisitor.VisitNew(NewExpression newExpression) at System.Linq.Expressions.NewExpression.Accept(ExpressionVisitor visitor) at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.RelationalProjectionExpressionVisitor.Visit(Expression expression) at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.VisitSelectClause(SelectClause selectClause, QueryModel queryModel) at Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.VisitSelectClause(SelectClause selectClause, QueryModel queryModel) at Remotion.Linq.Clauses.SelectClause.Accept(IQueryModelVisitor visitor, QueryModel queryModel) at Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel) at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.VisitQueryModel(QueryModel queryModel) at Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.VisitQueryModel(QueryModel queryModel) at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.CreateQueryExecutor[TResult](QueryModel queryModel) at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](QueryModel queryModel) at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](Expression query, INodeTypeProvider nodeTypeProvider, IDatabase database, IDiagnosticsLogger
1, введите contextType) в Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler. <> c__DisplayClass15_0 1.<Execute>b__0() at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func
1 компилятор) в Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCueryCueryCuCareCache 1 compiler) at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query) at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression) at System.Linq.Queryable.SingleOrDefault[TSource](IQueryable
1 источник) в Features.Topic.TopicMessagesQueries.getTopic (контекст RbbContext, Int32 entityFetchLimit, Int32 topicId) в TopicQueries.cs: строка 20 в Features.Topic.TopicService.getTopic (контекст RbbContext, topicopuQuery в32) TopicService.cs: строка 43 в Features.Topic.TopicController.Get (идентификатор Int32) в TopicController.cs: строка 34}
Я также хочу получить отношение пользователей из сообщений, я попытался добавить еще Select()
внутрь t.Messages
, но это также не сработало.
Я не могу найти похожие ссылки в google / stackoverflow запросов с двухуровневыми отношениями и условиями отношений.
Может кто-нибудь здесь может направить меня, чтобы получить этот запрос правильно?