c# - 如何选择列的最大值并检索多个结果?

标签 c# sql-server entity-framework entity-framework-6 asp.net-web-api2

我很难理解如何在我的 ASP.NET Web API v2 项目中使用 Entity Framework 6 和 SQL Server 构建我的 SQL 查询。

我的表结构:Computers 表是我的软件已清点的所有计算机的根表。它包含被其他表用作外键的列 ComputerID

我可以使用以下查询检索一台计算机,包括我拥有的所有信息:

Computer computer = ComputersDbContext.Computers
                   ... more includes....
                    .Include("Computer_Win_Installed_Software")
                   ... more includes....
                    .Where(a => a.ComputerId == computerId)
                       .First(t => t.TenantId == tenantId);

如您所见,我有另一个名为 Computer_Win_Installed_Software 的表,它存储了系统上安装的所有软件。它看起来像这样:

IdentityKey | ComputerID (FK) | Softwarename     | EntryTimestamp
------------+-----------------+------------------+--------------
          1 |               1 | Some Software    | 1547241345 
          2 |               1 | Another Software | 1547241345 

EntryTimestamp 是一个 Unix 时间戳,它对每次 list 运行都是唯一的,并且对于在该运行中发现的所有软件都是相同的。现在,如果系统再次清点,表格将如下所示:

IdentityKey | ComputerID (FK) | Softwarename       | EntryTimestamp
------------+-----------------+--------------------+---------------
          1 |               1 | Some Software      |     1547241345 
          2 |               1 | Another Software   |     1547241345 
          3 |               1 | Some Software      |     1886454564 
          4 |               1 | Another Software   |     1886454564 
          5 |               1 | Even More Software |     1886454564 

我想保留历史数据,所以我需要保留旧条目。

我的问题是我上面的 EF 查询将在结果对象中返回所有这些条目。

如何更改我的查询以便它只返回:

IdentityKey | ComputerID (FK) | Softwarename       | EntryTimestamp
------------+-----------------+--------------------+---------------
          3 |               1 | Some Software      |     1886454564 
          4 |               1 | Another Software   |     1886454564 
          5 |               1 | Even More Software |     1886454564 

我考虑过使用 2 个查询:

  • 第一个查询:我检查 EntryTimestamp 的最大值
  • 第二个查询:像这样:

    Computer computer = ComputersDbContext.Computers
                            .Include("Computer_Win_Installed_Software")      
                            .Where(a => a.ComputerId == computerId)
                            .Where(b => b.Computer_Win_Installed_Software.EntryTimestamp == EntryTimestamp)
                            .First(t => t.TenantId == tenantId);
    

但 Intellisense 立即对我尖叫 :D

我也想过只选择 MAX() 列的 EntryTimestamp ;但我什至不能在查询代码中使用 b.Computer_Win_Installed_Software.EntryTimestamp

当我写: .Where(b => b.Computer_Win_Installed_Software 时,它​​不会将任何列列为可用选项。

我认为这是因为 EF 中的 Computer_Win_Installed_Software 类是 ICollection<Computer_Win_Installed_Software> 类型。与 Computers 表都具有一对多关系的其他表也存在同样的问题。 另一个表与 Computers 表具有 1 对 1 的关系,我可以在那里选择所有列。

我 super 困惑。

是的,我搜索了谷歌,但找不到任何帮助我的东西。去这里的正确方法是什么?

编辑:添加模型

数据库上下文:

public class DbEntities : DbContext
{
    public virtual DbSet<Agent> Agents { get; set; }     
    public virtual DbSet<Computer_Win_Installed_Software> ComputerWinInstalledSoftware { get; set; }      
    public DbSet<Computer> Computers { get; set; }
}

计算机的 EF 模型:

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated from a template.
//
//     Manual changes to this file may cause unexpected behavior in your application.
//     Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ProjectName
{
    using System;
    using System.Collections.Generic;

    public partial class Computer
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public Computer()
        {
            this.Computer_Win_Installed_Software = new HashSet<Computer_Win_Installed_Software>();            
        }

        public int ComputerId { get; set; }
        public int TenantId { get; set; }
        public virtual Agent Agent { get; set; }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<Computer_Win_Installed_Software> Computer_Win_Installed_Software { get; set; }

    }
}

Computer_Win_Installed_Software 的 EF 模型:

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated from a template.
//
//     Manual changes to this file may cause unexpected behavior in your application.
//     Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace KysoWebApi
{
    using System;
    using System.Collections.Generic;

    public partial class Computer_Win_Installed_Software
    {
        public int ComputerId { get; set; }
        public string SoftwareName { get; set; }
        public Nullable<double> SoftwareVersion { get; set; }
        public Nullable<bool> IsServerSoftware { get; set; }
        public Nullable<int> SoftwareVendorId { get; set; }
        public string SoftwareIs32or64bits { get; set; }
        public int ComputerWinInstalledSoftwareEntryId { get; set; }
        public string EntryTimestamp { get; set; }

        public virtual Computer Computer { get; set; }
    }
}

最佳答案

因此,对于给定的 Computer , ICollection<Computer_Win_Installed_Software> Computer_Win_Installed_Software总是会包含所有相关行与所有 EntryTimestampts .你不能(轻松地)filter包括的实体。

因此,相反,只返回过滤后的实体:

var computer = ComputersDbContext.Computers
                .Where(a => a.ComputerId == computerId)
                .First(t => t.TenantId == tenantId);
var cwis = computer
            .Computer_Win_Installed_Software
                .Where(b => b.EntryTimestamp == EntryTimestamp);

当然,我不确定这是你真正想做的,你可能有一个 XY Problem .

您能否尝试不包括相关对象,而仅针对它们进行查询?

var computer = ComputersDbContext.Computers
                .Where(a => a.ComputerId == computerId)
                .First(t => t.TenantId == tenantId);
                .Where(b => b.Computer_Win_Installed_Software.EntryTimestamp == EntryTimestamp);

关于c# - 如何选择列的最大值并检索多个结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52936354/

相关文章:

c# - 根据行类型将父子表映射到其他表

c# - EF Code First 约定允许 ICollection<T> 属性为空集合而不是 null?

c# - 使用 Eval 的空值条件语句

c# - 与应用程序的文件类型关联 (C#)

c# - 在抛出的 clr 异常上创建核心转储

c# - 从 SQL Server 检索到的日期格式错误

c# - 如何获取存储过程的返回值

entity-framework - 在不知道父 ID 的情况下添加实体

c# - EF 中的可选 DatabaseGenerated 属性

c# - 为什么我不能在 LINQ 语句中执行多于一层的包含?