C#Linq连接有效,但是相同的结构化Linq GroupJoin失败

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

我有两个实体-客户和工作。客户与0到许多工作相关联。

客户端如下:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using JobsLedger.INTERFACES;

namespace JobsLedger.DATA.ENTITIES
{
#nullable enable
    public class Client : IEntityBase, IAuditedEntityBase
    {
        public Client()
        {
            ClientNotes = new List<Note>();
            Jobs = new List<Job>();
        }

        [Key]
        public int Id { get; set; }
        public string ClientNo { get; set; } = default!;
        public bool Company { get; set; }
        public string? CompanyName { get; set; }
        public string? Abn { get; set; }
        public bool IsWarrantyCompany { set; get; }
        public bool RequiresPartsPayment { set; get; }
        public string? ClientFirstName { get; set; }
        public string ClientLastName { get; set; } = default!;
        public string? Email { get; set; }
        public string? MobilePhone { get; set; }
        public string? Phone { get; set; }
        public string? Address1 { get; set; }
        public string? Address2 { get; set; }
        public string? BankName { get; set; }
        public string? BankBSB { get; set; }
        public string? BankAccount { get; set; }
        public bool Active { get; set; }
        public DateTime? DateDeActivated { get; set; }
        public bool Activity { get; set; }

        // One warranty company client to a job.
        public int? WarrantyCompanyId { get; set; }

        public virtual Job? WarrantyCompany { get; set; }

        // One suburb to a client.
        public int? SuburbId { get; set; }
        public virtual Suburb? Suburb { get; set; }

        // If its a warranty company then we simply link it one to one to the brand id.
        public virtual Brand? Brand { get; set; }

        // Multiple notes for each client.
        public virtual ICollection<Note> ClientNotes { get; set; }

        // Multiple jobs for each client.
        public virtual ICollection<Job> Jobs { get; set; }

        public virtual ICollection<Job> WarrantyCompanyJobs { get; } = default!;
    }
#nullable disable
}

工作如下:

using System.Collections.Generic;
using JobsLedger.INTERFACES;

namespace JobsLedger.DATA.ENTITIES
{
    public class Job : IEntityBase, IAuditedEntityBase
    {
        public Job()
        {
            JobNotes = new List<Note>();
            Visits = new List<Visit>();
        }

        public string? JobNo { get; set; }
        public string? AgentJobNo { get; set; }


        public int ClientId { get; set; } = default!;
        public virtual Client Client { get; set; } = default!;

        public int? BrandId { get; set; }
        public virtual Brand? Brand { get; set; }

        public int? TypeId { get; set; }
        public virtual JobType? Type { get; set; }

        public int? StatusId { get; set; }
        public virtual Status? Status { get; set; }

        public int? WarrantyCompanyId { get; set; }
        public virtual Client? WarrantyCompany { get; set; }

        public string? Model { get; set; }
        public string? Serial { get; set; }
        public string? ProblemDetails { get; set; }
        public string? SolutionDetails { get; set; }
        public virtual ICollection<Note> JobNotes { get; set; }

        public virtual ICollection<Visit> Visits { get; }

        public int Id { get; set; }
    }
#nullable disable
}

此Linq Join有效,并且我返回ClientIndexDtos的列表。

    public IQueryable<ClientIndexDto> GetClients()
    {
        var result = this._context.Clients.Join(this._context.Jobs, c => c.Id, j => j.Id, (c, j) =>
            new ClientIndexDto
            {
                Id = c.Id,
                ClientNo = c.ClientNo,
                Active = c.Active,
                ClientFirstName = c.ClientFirstName,
                ClientLastName = c.ClientLastName,
                Company = c.Company,
                CompanyName = c.CompanyName,
                MobilePhone = c.MobilePhone,
                IsWarrantyCompany = c.IsWarrantyCompany,
                //JobsCount = j.Count().ToString(CultureInfo.CurrentCulture)
            });
        return result;
    }

但是..我想要每个客户的工作数量(如果有)...所以我问了this question on SO,建议这样做:

    public IQueryable<ClientIndexDto> GetClients()
    {
        var result = this._context.Clients.GroupJoin(this._context.Jobs, c => c.Id, j => j.Id, (c, j) =>
            new ClientIndexDto
            {
                Id = c.Id,
                ClientNo = c.ClientNo,
                Active = c.Active,
                ClientFirstName = c.ClientFirstName,
                ClientLastName = c.ClientLastName,
                Company = c.Company,
                CompanyName = c.CompanyName,
                MobilePhone = c.MobilePhone,
                IsWarrantyCompany = c.IsWarrantyCompany,
                JobsCount = j.Count().ToString(CultureInfo.CurrentCulture)
            });
        return result;
    }

虽然它适用于联接版本,但在使用groupJoin运行时出现以下错误。

The LINQ expression 'DbSet<Client>()
    .GroupJoin(
        inner: DbSet<Job>(), 
        outerKeySelector: c => c.Id, 
        innerKeySelector: j => j.Id, 
        resultSelector: (c, j) => new ClientIndexDto{ 
            Id = c.Id, 
            ClientNo = c.ClientNo, 
            Active = c.Active, 
            ClientFirstName = c.ClientFirstName, 
            ClientLastName = c.ClientLastName, 
            Company = c.Company, 
            CompanyName = c.CompanyName, 
            MobilePhone = c.MobilePhone, 
            IsWarrantyCompany = c.IsWarrantyCompany 
        }
    )' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.

[我注意到,URL-https://go.microsoft.com/fwlink/?linkid=2101038讨论了客户端-服务器的评估...好吧,我自然希望在数据库中进行此评估,但是对于为什么一个(Join)畅通而另一个(GroupJoin)失败的原因感到困惑。] >

有人可以回答为什么它先不起作用,然后告诉我需要做什么来修复它。除了需要知道每个客户端上有多少工作外,我将使用Join。 GroupJoin将给我,如果我能使它正常工作...

我知道我希望在数据库端执行它,即获取一个IQueryable等,这样它就不会将多余的记录拖回客户端。”>

任何帮助表示赞赏。

我有两个实体-客户和工作。客户有0到许多与之关联的工作。客户端如下:使用系统;使用System.Collections.Generic;使用System.ComponentModel ....

c# linq linq-to-sql entity-framework-core
1个回答
0
投票

您必须了解实现IQueryable的对象与实现IEnumerable的对象之间的区别。

IEnumerable代表相似项目的序列。您可以获取序列的第一个元素,一旦获得了该元素,就可以获取下一个元素。

© www.soinside.com 2019 - 2024. All rights reserved.