简体   繁体   English

计数 Linq 查询与多连接 EF

[英]Count in Linq query with multiple join EF

Hi Helpies I am new to EF and linq queries嗨 Helpies 我是 EF 和 linq 查询的新手

        var chatEntryDetails = await
            (
                from chatEntry in dbChatEntry
                where chatEntry.ChatId == chat.Id
                join groupMembers in dbGroupMember on chatEntry.GroupMemberId equals groupMembers.Id
                join user in dbUser on groupMembers.UserId equals user.Id
                join countChatEntryUserStatus in dbChatEntryUserStatus.Where(e => e.DateReadByUser != null).Count() on chatEntry.Id equals countChatEntryUserStatus.ChatEntryId
                join chatEntryUserStatus in dbChatEntryUserStatus.Where(e => e.GroupMemberId == groupMemberId) on chatEntry.Id equals chatEntryUserStatus.ChatEntryId into ce
                from chatEntryUserStatus in ce.DefaultIfEmpty()
                orderby chatEntry.CreateDateTime descending
                select new ChatEntryDetails
                {
                    UserId = user.Id, GreetingName = user.GreetingName, GroupMemberId = chatEntry.GroupMemberId,
                    CreateDateTime = chatEntry.CreateDateTime, Details = chatEntry.Details, ChatType = ToApi(chatEntry.ChatType),
                    DateReadByUser = chatEntryUserStatus.DateReadByUser, ChatEntryId = chatEntry.Id, ReadByCount = countChatEntryUserStatus
                }
            )
            .PerPage(page, perPage)
            .ToListAsync();

When Executing this I got the following error执行此操作时出现以下错误

Could not find an implementation of the query pattern for source type 'IQueryable<<anonymous type: <anonymous type: <anonymous type: <anonymous type: ChatEntryDb chatEntry, GroupMemberDb groupMembers> <>h__TransparentIdentifier0, UserDb user> <>h__TransparentIdentifier1, IEnumerable<ChatEntryUserStatusDb> ce> <>h__TransparentIdentifier2, ChatEntryUserStatusDb chatEntryUserStatus>>'.  'Join' not found. [UserServerApiLib]

Everything works fine without this line没有这条线一切正常

join countChatEntryUserStatus in dbChatEntryUserStatus.Where(e => e.DateReadByUser != null).Count() on chatEntry.Id equals countChatEntryUserStatus.ChatEntryId

Here I want the count chatEntryUserStatus where DateReadByUser is not null This line is supposed to get the count from chatEntryUserStatus table with few conditions there is one table chatEntry and they related as chatEntry.id = chatEntryUserStatus.ChatEntryId and for every chatEntry it has multiple records in chatEntryUserStatus so I want that count from chatEntryUserStatus for every chatEntry在这里我想要计数 chatEntryUserStatus 其中 DateReadByUser 不是 null 此行应该从 chatEntryUserStatus 表中获取计数,但条件很少有一个表 chatEntry 并且它们与 chatEntry.id = chatEntryUserStatus.ChatEntryId 相关,并且对于每个 chatEntry 它都有多条记录chatEntryUserStatus 所以我希望每个 chatEntry 的 chatEntryUserStatus 计数

If not count then If I can get all the chatEntryUserStatus records for every chatEntry如果不算数,那么如果我可以获得每个 chatEntry 的所有 chatEntryUserStatus 记录

Thanks in advance提前致谢

Based on基于

Yes navigation properties are there是的,导航属性在那里

and looking at this Linq statement:并查看此 Linq 声明:

var chatEntryDetails = await
(
    from chatEntry in dbChatEntry
    where chatEntry.ChatId == chat.Id
    join groupMembers in dbGroupMember on chatEntry.GroupMemberId equals groupMembers.Id
    join user in dbUser on groupMembers.UserId equals user.Id
    join countChatEntryUserStatus in dbChatEntryUserStatus.Where(e => e.DateReadByUser != null).Count() on chatEntry.Id equals countChatEntryUserStatus.ChatEntryId
    join chatEntryUserStatus in dbChatEntryUserStatus.Where(e => e.GroupMemberId == groupMemberId) on chatEntry.Id equals chatEntryUserStatus.ChatEntryId into ce
    from chatEntryUserStatus in ce.DefaultIfEmpty()
    orderby chatEntry.CreateDateTime descending
    select new ChatEntryDetails
    {
        UserId = user.Id, 
        GreetingName = user.GreetingName, 
        GroupMemberId = chatEntry.GroupMemberId,
        CreateDateTime = chatEntry.CreateDateTime, 
        Details = chatEntry.Details, 
        ChatType = ToApi(chatEntry.ChatType),
        DateReadByUser = chatEntryUserStatus.DateReadByUser, 
        ChatEntryId = chatEntry.Id, 
        ReadByCount = countChatEntryUserStatus
    }
}
.PerPage(page, perPage)
.ToListAsync();

Then this looks like you may be able to leverage those navigation properties something like:然后看起来您可以利用这些导航属性,例如:

var chatEntryDetails = await context.ChatEntries
    .Where(c => c.Chat.Id == chatId)
    .Select(c => new ChatEntryDetails
    {
        UserId = c.GroupMember.User.Id,
        GreetingName = c.GroupMember.User.GreetingName,
        GroupMemberId = c.GroupMember.Id,
        CreateDateTime = c.CreateDateTime,
        Details = c.Details,
        ChatType = c.ChatType, 
        DateReadByUser = c.ChatEntryUserStatuses
            .Max(s => s.CreateDateTime),
        ChatEntryId = c.Id,
        ReadByCount = c.ChatEntryUserStatuses.Count()
   }).Skip(pageCount * pageSize)
   .Take(pageSize)
   .ToListAsync();

Which is considerably simpler than sifting through joins.这比通过连接筛选要简单得多。 The two deviations that you may need to look at are the ToApi() modifier that was on the ChatType, and the PerPage() method which seems to provide pagination.您可能需要查看的两个偏差是 ChatType 上的ToApi()修饰符和似乎提供分页的PerPage()方法。 Anything in the Select needs to ultimately boil down to SQL through EF, so there's a good chance that even without the original "count" join issue, that ToApi() would have triggered an exception. Select中的任何内容最终都需要通过 EF 归结为 SQL,因此即使没有最初的“计数”连接问题, ToApi()也很有可能会触发异常。 (Earlier EF Core versions would have pulled the query client-side when detecting something like that. It saves you from an exception but usually kills the performance and memory footprint for the query) If I had to guess I'd say this is translating a string or numeric value into another value suited to the consumer of this data. (早期的 EF Core 版本在检测到类似的东西时会拉取查询客户端。它可以让您免于异常,但通常会破坏查询的性能和 memory 占用空间)如果我不得不猜测我会说这是翻译将字符串或数值转换为适合此数据使用者的另一个值。 If that is the case where you want to translate values such as 1,2,3,4 to "A","B","C","D" then this can be a bit tricky.如果您想将诸如 1、2、3、4 之类的值转换为“A”、“B”、“C”、“D”,那么这可能有点棘手。 Inside the LINQ expression you can use (? :) Ie:在 LINQ 表达式中,您可以使用 (? :) 即:

ChatType = c.ChatType == 1 ? "A" : c.ChatType == 2 ? "B" : c.ChatType == 3 ? "C" : c.ChatType == 4 ? "D" : "?"

which is rather messy.这是相当混乱的。 Instead, I would typically recommend populating ChatType as-is in the ViewModel (ChatEntryDetails) and add a translated ApiChatType property which does a switch() statement across ChatType to return the appropriate translation.相反,我通常建议在 ViewModel (ChatEntryDetails) 中按原样填充 ChatType,并添加一个已翻译的 ApiChatType 属性,该属性跨 ChatType 执行switch()语句以返回适当的翻译。

For pagination use the stock-standard Linq pagination methods of Skip and Take to ensure these are translated to the SQL query as well.对于分页,使用标准的 Linq 分页方法SkipTake以确保这些也被转换为 SQL 查询。 We can get the latest CreateDateTime from the user statuses using Max , though an OrderByDescending + FirstOrDefault + Select can work here as well.我们可以使用Max从用户状态中获取最新的 CreateDateTime,尽管OrderByDescending + FirstOrDefault + Select也可以在这里工作。 readByCount is provided by just asking for the Count of the related statuses. readByCount 是通过询问相关状态的Count来提供的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM