我正在寻找EntityFramework Core Bug的解决方法。我正在尝试编写一个对自身进行过滤的查询
Disclaimer:我做的事情比通过显式userId过滤要复杂得多,为了简化描述问题,我仅使用315。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ConversationSubscription>()
.HasQueryFilter(x => x.Conversation.ConversationSubscriptions
.Select(c => c.UserId).Contains(315));
}
由于查询过滤器正尝试访问其过滤器所在的实体,因此它以无限循环结束。由于我们使用的是ModelBuilder而不是DBSet,因此无法将其标记为IgnoreQueryFilters
所以我尝试使用当前上下文对其自身进行过滤
modelBuilder.Entity<ConversationSubscription>().HasQueryFilter(x =>
this.Set<ConversationSubscription().AsNoTracking().IgnoreQueryFilters()
.Where(cs => cs.ConversationId == x.ConversationId)
.Select(c => c.UserId)
.Contains(315));
但是这会抛出InvalidOperationException
最有可能,因为我们试图在OnModelCreating
完成之前使用上下文。
[我觉得我有办法解决这个问题,如果我能将ConversationSubsriptions选择为AnonymousType,这样就不会对其进行过滤。
编辑:我试图使用匿名类型来破解它,没有运气。
modelBuilder.Entity<ConversationSubscription>().HasQueryFilter(c =>
x => x.Conversation.Messages.Select(m => new {
Value = m.Conversation.ConversationSubscriptions.Distinct()
.Select(cs => cs.UserId).Contains(c.Variable(this._userId))
}).FirstOrDefault().Value);
也许我在约翰尼身上缺少明显的东西,所以如果我偏离正常,我深表歉意。
但是我觉得您正在这样做:
From conversation subscriptions, join conversations, then join conversation subscriptions where user id = 315
虽然您可以/应该这样做:
From conversation subscriptions where user id = 315, join conversations.
我看不到查询中的往返行程是必需的,因为它看起来像您是在ConversationSubscription中进行查询。在这样的查询中,简单的include将仅返回用户有权访问的对话和对话预订。那不是您想要退回的东西吗?
var result = context.ConversationSubscriptions.Include(c => c.Conversation).ToList();
private int _userId = 315;
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ConversationSubscription>()
.HasQueryFilter(x => x.UserId.Contains(_userId));
}
查询过滤器最初不支持访问导航属性或数据库集。看起来EF Core 3.0消除了这些限制(可能是由于新的Single SQL statement per LINQ query模式),具有以下限制/错误:
[AsNoTracking()
和AsTracking()
-不支持,这很有意义,因为查询过滤器总是转换为SQL。
[Include
/ ThenInclude
-允许,但出于相同原因而忽略。
IgnoreQueryFilters
-不支持。由于可以将其用于解决以下情况,因此可以将其视为错误。
交叉引用过滤器(例如,实体A
过滤器使用实体B
,而实体B
过滤器使用实体A
))通过导航属性或数据库集-导致StackOverflowException
,因为过滤器试图使用每个其他。这是一个错误。
通过导航属性的自引用过滤器-与#4相同的错误,应类似于#6。
通过数据库集的自引用过滤器-受支持的(!),在过滤器子查询中始终被忽略。
话虽这么说,幸运的是#6支持您的情况,即您第二次尝试,只是删除了不受支持的AsNoTracking()
和IgnoreQueryFilters()
:
modelBuilder.Entity<ConversationSubscription>().HasQueryFilter(x =>
this.Set<ConversationSubscription()
.Where(cs => cs.ConversationId == x.ConversationId)
.Select(c => c.UserId)
.Contains(315));