Я изо всех сил пытаюсь понять, как построить мой SQL-запрос с использованием Entity Framework 6 и SQL Server в моем проекте ASP.NET Web API v2.
Структура моей таблицы: таблица 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, уникальная для каждого запуска инвентаризации и одинаковая для всего программного обеспечения, обнаруженного при этом запуске.Теперь, если система будет снова инвентаризована, таблица будет выглядеть следующим образом:
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
, он не перечисляет ни один из столбцов в качестве доступных параметров.
Я думаю, что этопотому что класс Computer_Win_Installed_Software
в EF имеет тип ICollection<Computer_Win_Installed_Software>
.Это та же проблема с другими таблицами, которые имеют отношение 1 ко многим к таблице Computers
.Другая таблица имеет отношение 1 к 1 к таблице Computers
, и там я могу выбрать все столбцы.
Я очень запутался.
И да, я сделал Google, но я не мог найти ничего, что помогло бы мне.Какой правильный путь здесь?
Редактировать: добавленные модели
DBContext:
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; }
}
}
EF Model для Computer_Win_Installed_Software:
//------------------------------------------------------------------------------
// <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; }
}
}