问题概述:
我有数据库表,描述了使用Web服务从多个设备中收集数据并存储到集中式数据库中的情况。
为了提高性能(更快的查询和多索引分组),存储结果的表被故意去规范化。 我正在使用Entity Framework和Linq进行数据访问。
我需要适当地 设计Linq查询,实现层次分组和投影。
设备数据库建模概述:
目前我有两种类型的设备
1. Rfid 设备
第一个表是 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
--
)
每个RFID读卡器都可以附加到特定的测量区域,该区域是为特定的结构描述的。
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个单独的传感器。例如,一个单独的探针可以获取温度数据。
第二个表是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
--
)
查询、分组和投影问题:
正如你在上面看到的,我们有两个包含由两种设备收集的数据的分散表。 是的,我们可以假设 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问题,就像这个问题的主题一样。