c# - 在 Entity Framework Core 中获取与条件的关系
问题描述
我正在开发一个带有 .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()
and 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()
and时,它可以工作(但没有我想要实现的条件),但如果我保留它们,它会返回错误:Take()
Select()
{System.ArgumentException:
1[Microsoft.EntityFrameworkCore.Storage.ValueBuffer]' cannot be used for parameter of type 'System.Collections.Generic.IEnumerable
方法“System.Collections.Generic.IEnumerable”的“System.Collections.Generic.IEnumerable 1[Dal.Models.Message]”类型的表达式1[Dal.Models.Message] _ToEnumerable[Message](System.Collections.Generic.IEnumerable
1[Dal.Models.Message])'参数名称:在 System.Dynamic.Utils.ExpressionUtils.ValidateOneArgument 的 arg0(MethodBase 方法,ExpressionType nodeKind,表达式参数,ParameterInfo pi,String methodParamName,String argumentParamName,Int32 索引)在 System.Linq .Expressions.Expression.Call(MethodInfo method, Expression arg0) at Microsoft.EntityFrameworkCore.Query.ExpressionVisitor.ProjectionExpressionVisitor.VisitSubQuery(SubQueryExpression expression) at Remotion.Linq.Clauses.Expressions.SubQueryExpression.Accept(ExpressionVisitor visitor) at System.Linq。 Expressions.ExpressionVisitor.Visit(表达式节点)在 Microsoft.EntityFrameworkCore.Query.ExpressionVisitor.RelationalProjectionExpressionVisitor.Visit(表达式表达式)在 System.Linq.Expressions.ExpressionVisitor.VisitAndConvert[T](ReadOnlyCollection1 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 个记录器,在 Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler 中键入 contextType。<>c__DisplayClass15_01.<Execute>b__0() at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func
1 个编译器在 Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](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 .TopicMessagesQueries.getTopic(RbbContext context, Int32 entitiesFetchLimit, Int32 topicId) 在 TopicQueries.cs: 第 20 行在 Features.Topic.TopicService.getTopic(RbbContext context, ITopicQueries topicQueries, Int32 topicId) 在 TopicService.cs: 第 43 行在 Features.Topic .TopicController.Get(Int32 id) 在 TopicController.cs:line 34}
我也想从消息中获取用户关系,我尝试Select()
在里面添加另一个t.Messages
,但这也没有用。
我在 google/stackoverflow 中找不到具有 2 级关系和关系条件的查询的类似引用。
这里的任何人都可以指导我正确地进行此查询吗?
解决方案
您正在返回一个匿名类型。您必须将最终输出投影到您的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();
推荐阅读
- r - plotHR (package Greg) - Spline-Plot - 根据 x 值手动设置危险比 = 1
- asp.net-mvc-5 - 如何将字符串数据类型绑定到 mVC5 中的下拉列表?
- postgresql - 无法在 Windows 上的 Postgres 数据库中创建 postGIS 扩展
- html - 如何使父元素下的子元素浮动全宽
- python - 修改作为函数内部参数传递的变量
- java - CheckedTextView 错误:android.content.res.Resources$NotFoundException:资源 ID #0x0
- kubernetes - Pod 错误:CrashLoopBackOff (GKE)
- firebase - 如何使用通过使用 REST API 获得的 userId 和令牌将文件上传到 Firebase 存储
- javascript - 是否可以一次更改网站上的所有锚标签属性?
- java - 使用 android studio 将数据导出到 google sheet:如何在活动之间传输变量?