我正在使用.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);
但现在我想在消息中添加一些条件:
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
的表达式'[Dal.Models.Message]'方法'System.Collections.Generic.IEnumerable1[Dal.Models.Message] _ToEnumerable[Message](System.Collections.Generic.IEnumerable
1 [ Dal.Models.Message])'System.Linq.Expressions中的参数名:arg0 at System.Dynamic.Utils.ExpressionUtils.ValidateOneArgument(MethodBase方法,ExpressionType nodeKind,Expression arguments,ParameterInfo pi,String methodParamName,String argumentParamName,Int32 index) System.Linq.Expressions上的Remotion.Linq.Clauses.Expressions.SubQueryExpression.Accept(ExpressionVisitor visitor)中的Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.ProjectionExpressionVisitor.VisitSubQuery(SubQueryExpression表达式)中的.Expression.Call(MethodInfo方法,Expression arg0)。 System.Linq.Expressions.ExpressionVisitor.VisitAndConvert [T]上的Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.RelationalProjectionExpressionVisitor.Visit(Expression expression)中的ExpressionVisitor.Visit(Expression node)(ReadOnly Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery中的Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler。&lt;&gt; c__DisplayClass15_01 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编译器的集合1.<Execute>b__0() at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func
1记录器,类型contextType)[TResult在TopicQueries.cs中的Features.Topic.TopicMessagesQueries.getTopic(RbbContext context,Int32 entitiesFetchLimit,Int32 topicId)中的(Object cacheKey,Func1 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 source):Features.Topic.TopicService.getTopic(RbbContext context)中的第20行,TopicService.cs中的ITopicQueries topicQueries,Int32 topicId):TopicController.cs中的Features.Topic.TopicController.Get(Int32 id)第43行:第34行
我还想从消息中获取用户关系,我尝试在Select()
内添加另一个t.Messages
,但这也无效。
我无法在google / stackoverflow中找到类似的关于具有2级关系和关系条件的查询的参考资料。
这里的任何人都可以指导我这个查询吗?
答案 0 :(得分:1)
您将返回匿名类型。您必须将最终输出投影到Topic
对象。这可能看起来有点难看,但它应该只打一次数据库并获得所需的记录。运行探查器以查看生成的查询。
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()
.AsEnumerable().Select(x => new Topic
{
TopicId = x.TopicId ,
Bookings = x.Messages.ToList()
}).SingleOrDefault();