.. Net核心自访问查询过滤器

问题描述 投票:0回答:2

我正在寻找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);
c# .net-core entity-framework-core
2个回答
0
投票

也许我在约翰尼身上缺少明显的东西,所以如果我偏离正常,我深表歉意。

但是我觉得您正在这样做:

  • 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));
}

0
投票

查询过滤器最初不支持访问导航属性或数据库集。看起来EF Core 3.0消除了这些限制(可能是由于新的Single SQL statement per LINQ query模式),具有以下限制/错误:

  1. [AsNoTracking()AsTracking()-不支持,这很有意义,因为查询过滤器总是转换为SQL。

  2. [Include / ThenInclude-允许,但出于相同原因而忽略。

  3. IgnoreQueryFilters-不支持。由于可以将其用于解决以下情况,因此可以将其视为错误。

  4. 交叉引用过滤器(例如,实体A过滤器使用实体B,而实体B过滤器使用实体A))通过导航属性或数据库集-导致StackOverflowException,因为过滤器试图使用每个其他。这是一个错误。

  5. 通过导航属性的自引用过滤器-与#4相同的错误,应类似于#6。

  6. 通过数据库集的自引用过滤器-受支持的(!),在过滤器子查询中始终被忽略。

话虽这么说,幸运的是#6支持您的情况,即您第二次尝试,只是删除了不受支持的AsNoTracking()IgnoreQueryFilters()

modelBuilder.Entity<ConversationSubscription>().HasQueryFilter(x => 
    this.Set<ConversationSubscription()
        .Where(cs => cs.ConversationId == x.ConversationId)
              .Select(c => c.UserId)
              .Contains(315));
© www.soinside.com 2019 - 2024. All rights reserved.