问题概述:
我有数据库表,这些表描述了使用 Web 服务从多个设备收集到集中式数据库的数据。
为了性能,存储结果的表被刻意去规范化:通过多个索引进行更快的查询和分组。 我正在使用 Entity Framework 和 Linq 进行数据访问。
我需要使用分层分组和投影正确设计 Linq 查询。
设备数据库建模概述:
目前我有两种类型的设备
1. 射频识别设备
第一个表是描述收集数据的标签的 RfidTag,1 个 RfidTag = 1 个单个传感器。因此,例如 1 个单标签可以获取有关温度的数据。
第二个表是 RfidReader,它描述了读取模块,该模块收集并发送来自附加标签的所有数据。对单个 RfidReader 附加 RfidTag 的数量没有限制。然而,一个单一的 RfidTag 可以在读取期间附加到一个单一的 RfidReader。
CREATE TABLE [dbo].[RfidTag]
(
Id INT IDENTITY(1,1),
CreatedDateTime DATETIME NOT NULL DEFAULT GETDATE(),
ModifiedDateTime DATETIME,
--
ReaderId INT NULL, -- Reference to reader
SensorTypeId INT NOT NULL, -- Reference to sensor type
SensorParameters NVARCHAR(50) NULL, -- Sensor parameters
Hex NVARCHAR(50) NOT NULL, -- Hex tag identifier stored as string
Name NVARCHAR(50) NOT NULL, -- Tag name
[Description] NVARCHAR(200) NULL, -- Tag description
--
)
CREATE TABLE [dbo].[RfidReader]
(
Id INT IDENTITY(1,1),
CreatedDateTime DATETIME NOT NULL DEFAULT GETDATE(),
ModifiedDateTime DATETIME,
--
Name NVARCHAR(20), -- Tag name
[Description] NVARCHAR(200), -- Tag description
SerialNumber NVARCHAR(12), -- Unique device serial name
--
)
每个 RfidReader都可以连接到针对特定结构描述的特定测量区域。
CREATE TABLE [dbo].[RfidReaderPlacement]
(
Id INT IDENTITY(1,1),
CreatedDateTime DATETIME NOT NULL DEFAULT GETDATE(),
--
ReaderId INT NOT NULL, -- Reference to Reader.
MeasurementZoneId INT NOT NULL, -- Reference to Measurement Zone.
StartDate DATETIME NOT NULL, -- Start date of reading.
StopDate DATETIME, -- End date of reading.
--
)
RfidTag 收集的单个数据保存在非规范化表中。该表存储了数百万条记录,并且负载非常重。从此表中,我们将使用 LINQ 查询收集数据。
CREATE TABLE [dbo].[RfidReading]
(
Id INT IDENTITY(1,1),
CreatedDateTime DATETIME NOT NULL DEFAULT GETDATE(),
ModifiedDateTime DATETIME,
--
ReaderPlacementId INT NOT NULL, -- Reference to Rfid Reader Placement
ConstructionId INT NOT NULL, -- Reference to Construction
MeasurementZoneId INT NOT NULL, -- Reference to Measurement Zone
ReaderId INT NOT NULL, -- Reference to Rfid Reader
TagId INT NOT NULL, -- Reference to Rfid Tag
SensorTypeId INT NOT NULL, -- Reference to Sensor Type
ReadingDate DATETIME NOT NULL, -- Reading date
Value FLOAT NOT NULL -- Measured value
--
)
2. ZigBee 设备
第一个表是 ZigBeeNodeProbe,它描述了收集数据的单个探针,1 个 ZigBeeNodeProbe = 1 个单个传感器。因此,例如 1 个单探头可以获取有关温度的数据。
第二个表是 ZigBeeNode,它描述了包含附加探针的单个设备,1 个 ZigBeeNode = 3 个 ZigBeeNodeProbes。
第三个表是 ZigBeeReader,它描述了从附加节点收集所有数据并将其发送到它的读取模块。对单个 ZigBeeReader 的附加 ZigBeeNodes(已附加 ZigBeeNodeProbes)的数量没有限制。然而,一个单一的 ZigBeeNode 可以在读取期间连接到一个单一的 ZigBeeReader。
CREATE TABLE [dbo].[ZigBeeNodeProbe]
(
Id INT IDENTITY(1,1),
CreatedDateTime DATETIME NOT NULL DEFAULT GETDATE(),
--
NodeId INT NULL, -- Reference to node
SensorTypeId INT NOT NULL, -- Reference to sensor type
SensorParameters NVARCHAR(50) NULL, -- Sensor parameters
SocketNumber INT NOT NULL, -- Socket number used in parent ZigBeeNode
Name NVARCHAR(50) NOT NULL, -- Node name
[Description] NVARCHAR(200) NULL, -- Node description
--
)
CREATE TABLE [dbo].[ZigBeeNode]
(
Id INT IDENTITY(1,1),
CreatedDateTime DATETIME NOT NULL DEFAULT GETDATE(),
ModifiedDateTime DATETIME,
--
ReaderId INT NULL, -- Reference to reader
NetworkAddress NVARCHAR(50) NOT NULL,-- Node address in ZigBee network
Name NVARCHAR(50) NOT NULL, -- Given name
[Description] NVARCHAR(200) NULL, -- Tag description
SocketCount INT NOT NULL DEFAULT 0, -- Count of available sockets to plug in probe
NodeFrequency INT NULL, -- Node frequency
)
CREATE TABLE [dbo].[ZigBeeReader]
(
Id INT IDENTITY(1,1),
CreatedDateTime DATETIME NOT NULL DEFAULT GETDATE(),
ModifiedDateTime DATETIME,
--
Name NVARCHAR(20), -- Tag name
[Description] NVARCHAR(200), -- Tag description
SerialNumber NVARCHAR(12), -- Unique device serial name
--
)
每个 ZigBeeReader都可以连接到针对特定结构描述的特定测量区域。
CREATE TABLE [dbo].[ZigBeeReaderPlacement]
(
Id INT IDENTITY(1,1),
CreatedDateTime DATETIME NOT NULL DEFAULT GETDATE(),
--
ReaderId INT NOT NULL, -- Reference to Reader.
MeasurementZoneId INT NOT NULL, -- Reference to Measurement Zone.
StartDate DATETIME NOT NULL, -- Start date of reading.
StopDate DATETIME, -- End date of reading.
--
)
ZigBeeNodeProbe 收集的单个数据保存在非规范化表中。该表存储了数百万条记录,并且负载非常重。从此表中,我们将使用 LINQ 查询收集数据。
CREATE TABLE [dbo].[ZigBeeReading]
(
Id INT IDENTITY(1,1),
CreatedDateTime DATETIME NOT NULL DEFAULT GETDATE(),
ModifiedDateTime DATETIME,
--
ReaderPlacementId INT NOT NULL, -- Reference to ZigBee Reader Placement
ConstructionId INT NOT NULL, -- Reference to Construction
MeasurementZoneId INT NOT NULL, -- Reference to Measurement Zone
ReaderId INT NOT NULL, -- Reference to ZigBee Reader
NodeId INT NOT NULL, -- Reference to ZigBee Node
ProbeId INT NOT NULL, -- Reference to ZigBee Node Probe
SensorTypeId INT NOT NULL, -- Reference to Sensor Type
ReadingDate DATETIME NOT NULL,-- Reading date
Value FLOAT NOT NULL -- Measured value
--
)
查询、分组和投影问题:
正如您在上面看到的,我们有 2 个分散的表,其中包含由 2 种提到的设备收集的数据。是的,我们可以假设 RfidTag 在业务建模中与 ZigBeeNodeProbe 几乎相同。
RfidReader
-- RFidTag
-- RFidTag
...
ZigBeeReader
-- ZigBeeNode
---- ZigBeeNodeProbe
---- ZigBeeNodeProbe
---- ZigBeeNodeProbe
-- ZigBeeNode
---- ZigBeeNodeProbe
---- ZigBeeNodeProbe
---- ZigBeeNodeProbe
...
现在我们必须查询这两个表,将不同表中的值投影到相同的视图模型中,并添加特定的分组来过滤数据。
常见场景:
我们想创建一个图表来显示特定测量区域的平均温度,请记住特定测量区域可能包含多个附加的阅读器(Rfid 和 ZigBee),因此我们必须提供一系列数据。
我正在使用必须启用的HightStock http://www.highcharts.com/products/highstock图表:
- 缩放 1 个月、3 个月、6 个月等。
- 从,到日期期间
- 导出功能
- 具有启用和禁用系列的图例
图表示例:
问题:
如何为分层数据创建 LINQ 分组和投影查询? 我们需要为 RfidReading 和 ZigBeeReading 表提供通用视图模型。
我的第一次尝试是这样的:
public class ReadingReaderDataModel
{
public string SeriesName { get; set; }
public ReadingPeriod ReadingPeriod { get; set; }
public IEnumerable<ReadingNodeDataModel> ReadingNodeDataModels { get; set; }
public ReadingReaderDataModel()
{
ReadingNodeDataModels = new List<ReadingNodeDataModel>();
}
}
public class ReadingNodeDataModel
{
public string NodeName { get; set; }
public IEnumerable<double> DataValues { get; set; }
public ReadingNodeDataModel()
{
DataValues = new LinkedList<double>();
}
}
public enum ReadingPeriod
{
OneMonth, ThreeMonths, SixMonths, YearToDay, OneYear, All
}
public enum ReaderType
{
Rfid, ZigBee
}
稍后我必须为 ASP.NET MVC 控制器设计 LINQ 投影,在这里我不知道如何创建正确的查询,该查询必须包含按 OneMonth、ThreeMonths、SixMonths、YearToDay、OneYear、All 分组的时间段的平均值。
谁能帮我设计这个高级 LINQ 查询?
编辑
请不要为大型数据集指出任何“建议”...
这不是关于性能的问题。
这个问题是关于复杂的 LINQ 查询。我正在寻找正确的 LINQ 代码,而不是像“那辆车更快,你应该尝试使用那辆车”这样的答案......请提供代码答案......如果你甚至不尝试理解场景并提供任何代码,请不要参加...
我特别添加了一个赏金来寻找 LINQ 的解决方案,因为它是高级 LINQ 问题,就像这个问题的主题一样。