我试图在2个不同的表上做一个联合,但我开始得到这个错误,因为更新到EF Core 8.完整的错误信息是:

InvalidOperationException:无法翻译设置操作 客户预测已经apply.考虑移动set操作 在最后一次" Select "呼叫之前

下面是我的代码:

            var query = dbContext.Servicing
                .Include(s => s.Customer)
                .Include(s => s.Pictures)
                .Where(s => s.CustomerId == customerId)
                .Where(i => i.Pictures.Count > 0)
                .Select(s => new SiteVisit
                {
                    Id = s.Id,
                    CustomerId = s.CustomerId,
                    CustomerName = s.Customer.Name,
                    Date = s.ServiceDate,
                    Category = SiteVisitCategory.Service,
                    ServicingPictures = s.Pictures,
                    InstallPictures = new List<Picture>(),
        
                })

                .Union(dbContext.Installs
                    .Include(i => i.Order)
                    .Include(i => i.Pictures)
                    .Where(i => i.Order.CustomerId == customerId)
                    .Where(i => i.Pictures.Count > 0)
                    .Select(i => new SiteVisit
                    {
                        Id = i.Id,
                        CustomerId = i.Order.CustomerId,
                        CustomerName = i.Order.CustomerName,
                        Date = i.InstallDate,
                        Category = SiteVisitCategory.Install,
                        InstallPictures = i.Pictures,
                        ServicingPictures = new List<Picture>()                       
                     
                    }))

                .OrderByDescending(v => v.Date)
                .AsNoTracking();

            var queryResults = await query.ToListAsync();

我试过移动"Where"子句,但总是出错. 有人能建议我可以try 的其他东西吗?

感谢大家的投入.抱歉没有澄清SiteVisit类是POCO.看起来EF Core无法处理不仅仅是简单的财产分配的预测.我只能假设早期版本的EF完全是在记忆中完成的.最后,我使用CONCAT(无论如何,数据将是唯一的)与单独的查询(根据一些贡献者的建议)检索图片.它读起来不像原文那么优雅,但它很有效.再次感谢

推荐答案

有一些问题EF是无法通过联合来解决的,虽然能够在单个查询中获得所有信息似乎很好,但您最好的 Select 将最有可能是在单独的查询中提取项目,在内存中合并结果(因为您无论如何都要加载数据),或者可能联合基础数据并分别提取图像.当使用投影到这个站点访问DTO/ViewModel时,我强烈推荐的一个细节是避免混合DTO和实体.在这种情况下,在SiteVisit中存储对Picture实体的引用.理想的情况下,将这些投影到POCO DTO类中,以及仅使用您需要的图片字段.即使大多数字段都是需要的,它也可以避免在处理Picture时,它是一个被跟踪的实体,还是来自实体的一些分离的和潜在的虚拟化的表示.

选项1:内存联合:

var serviceSiteVisits = await dbContext.Servicing
    .Where(s => s.CustomerId == customerId)
    .Where(i => i.Pictures.Count > 0)
    .Select(s => new SiteVisit
    {
        Id = s.Id,
        CustomerId = s.CustomerId,
        CustomerName = s.Customer.Name,
        Date = s.ServiceDate,
        Category = SiteVisitCategory.Service,
        ServicingPictures = s.Pictures.Select(p => new PictureDto
        {
            Id = p.Id,
            // ..
        }).ToList()
     }).ToListAsync();

var installSiteVisits = await dbContext.Installs
    .Where(i => i.Order.CustomerId == customerId)
    .Where(i => i.Pictures.Count > 0)
    .Select(i => new SiteVisit
    {
        Id = i.Id,
        CustomerId = i.Order.CustomerId,
        CustomerName = i.Order.CustomerName,
        Date = i.InstallDate,
        Category = SiteVisitCategory.Install,
        InstallPictures = i.Pictures.Selectp => new PictureDto
        {
            Id = p.Id,
            // ..
        }).ToList()
    }).ToListAsync();

var results = serviceSiteVisits.Concat(installSiteVisits)
    .OrderByDescending(v => v.Date)
    .ToList();

在您的SiteVisit ViewModel中,(和实体)有集合引用自初始化,以避免投影/群体中的代码负责初始化.例如,实体永远不应该公开集合的公共setter,因为滥用这些集合会扰乱变更跟踪.例如:

  public ICollection<PictureDto> ServicingPictures { get; protected set; } = new List<PictureDto>();

选项2:联合双投影与图片单独加载.

var initialResults = await dbContext.Servicing
    .Where(s => s.CustomerId == customerId)
    .Where(i => i.Pictures.Count > 0)
    .Select(s => new 
    {
        Id = s.Id,
        CustomerId = s.CustomerId,
        CustomerName = s.Customer.Name,
        Date = s.ServiceDate,
        Category = SiteVisitCategory.Service,
        ServicingPictureIds = s.Pictures.Select(p => p.Id).ToList(),
        InstallPictureIds = new List<int>(),
    })
    .Union(dbContext.Installs
        .Where(i => i.Order.CustomerId == customerId)
        .Where(i => i.Pictures.Count > 0)
        .Select(i => new 
        {
            Id = i.Id,
            CustomerId = i.Order.CustomerId,
            CustomerName = i.Order.CustomerName,
            Date = i.InstallDate,
            Category = SiteVisitCategory.Install,
            InstallPictureIds = i.Pictures.Select(p => p.Id).ToList(),
            ServicingPictureIds = new List<int>()                       
        })).OrderByDescending(v => v.Date)
            .ToListAsync();

var pictureIds = initialResults.SelectMany(x => x.ServicePictureIds)
    .Concat(initialResults.SelectMany(x => x.InstallPictureIds))
    .ToList();
var pictures = await dbContext.Pictures
    .Where(p => pictureIds.Contains(p.Id))
    .Select(p => new PictureDto
    {
        Id = p.Id,
        // ...
    }).ToListAsync();

var results = interimResults
    .Select(x => new SiteVisit
    {
        Id = x.Id,
        CustomerId = x.CustomerId,
        CustomerName = x.CustomerName,
        Date = x.Date,
        Category = x.Category,
        ServicingPictures = x.ServicingPictureIds
            .Select(pId => pictures.FirstOrDefault(p => p.Id == pId))
            .ToList();
        InstallPictures = x.InstallPictureIds
            .Select(pId => pictures.FirstOrDefault(p => p.Id == pId))
            .ToList();
    }).ToList();

老实说,在写完所有这些之后,它仍然可能不工作,所以我建议坚持更简单的选项1.:)双投影可以用来帮助摆脱一些棘手的情况,其中有属性或者EF不能向下转换为SQL.首先将原始值投影为匿名类型,然后执行第二个内存投影,该投影执行无法转换的步骤以获得最终结果.

Csharp相关问答推荐

如何将ref T*重新解释为ref nint?

编写DataAnnotations自定义验证器的多种方法

为什么C#Bigbit不总是相同的比特长度?

如何在NodaTime中为Instant添加一年?

.NET 6控制台应用程序,RabbitMQ消费不工作时,它的程序文件中的S

Thad.Sept()vs Task.Delay().Wait()

获取具有AutoFaces的所有IOptions对象的集合

在静态模式下实例化配置

在此系统上已禁用获取正在运行的脚本.&在ASP.NET Core Web API中

如果设置了另一个属性,则Newtonsoft JSON忽略属性

如何将字符串变量传递给JObject C#-无法加载文件或程序集';System.Text.Json

net中从位图获取坐标和绘制折线

LINQ to Entities中的加权平均值

在C#.NET项目中启动时,如何等待提升的PowerShell进程退出?

CRL已过期,但ChainStatus告诉我RevocationStatus未知

如何在mediatr命令中访问HttpContext而不安装弃用的nuget包

解决方案:延长ABP框架和ANGING OpenIddict中的令牌生命周期

如何在使用Google.Drive.apis.V3下载文件/文件夹之前压缩?

如何在特定时间间隔运行多个后台任务?

无法对包含字符串的列进行排序.请与实体框架联接