【发布时间】:2013-11-09 16:53:06
【问题描述】:
我们需要在 SQL Server 数据库中存储“设置”结构。一个“设置”有多个“通道”,可以有子通道。每个通道都可以有多个包含标准属性和值的“变量”。
此结构在 C# 项目中定义。所以,有一个Setup对象包含一个List,有一个Channel对象包含一个List和一个List。
我实际上通过创建一个设置表、一个带有设置外键和自引用的通道表以及一个带有通道外键的变量表来完成该项目。
c# 程序需要一些功能来列出现有设置、加载和保存。
我创建了一个存储过程来保存一个接受 3 个表参数的设置:设置(应该只包含一行)、通道和变量。输入参数仅包含实体的自然键。然后存储过程将它们插入或更新到数据库中。
为了加载一个设置,我创建了一个执行 3 次选择的存储过程。然后c#通过SqlCommand.ExecuteReader()读取它们。
问题:保存设置存储过程该死太复杂了。以下是简要的步骤。由于 Channels 的层次结构,这一切都变得更加复杂,因为我需要逐步处理层次结构的每个级别:
Parameter validity check
Check if Setup exists
if yes, update, keep its id (SetupID)
if not, insert, keep its id (SetupID)
Update SetupID in parameter tables Channel,Variable
Fetch ChannelID for channels given in parameters that do exist in the database
Fetch VariableID for variables given in parameters that do exist in the database
Delete channels and variables that do exist in database for that setup, but were not provided in the parameters
Channels should be recursively deleted, first the ones without children, then their parents etc.
Insert new Channels (given in parameters, not existing in the database)
Do it recursively, first for the ones without children, then, their parents, etc.
Every time you do some insert, update the respective ChannelID in the parameter tables
Update Channels given in parameters that do exist in the database
Insert new Variables (given in parameters, not existing in the database)
Update Variables given in parameters that do exist in the database
它转换为大约 250 行 T-SQL 代码,我花了 2 天时间编写和错误检查。它现在工作正常,但我相信它可以以更简单的方式完成。 有什么想法/cmets?
P.S.:保存在 XML 中不是一种选择,因为该项目的关键思想是能够查看所有属性并对其进行查询、验证、制作报告和统计等。
提前致谢!
更新:表创建脚本
CREATE TABLE [dbo].[Setup](
[SetupID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NOT NULL,
[Type] [nvarchar](4000) NULL,
[Info] [nvarchar](4000) NULL,
[FirstInserted] [datetime] NULL,
[LastUpdated] [datetime] NULL,
CONSTRAINT [PK$Setup] PRIMARY KEY CLUSTERED
([SetupID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE UNIQUE NONCLUSTERED INDEX [UQ$Setup$Name] ON [dbo].[Setup]
([Name] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Channel](
[ChannelID] [int] IDENTITY(1,1) NOT NULL,
[SetupID] [int] NOT NULL,
[Type] [nvarchar](50) NOT NULL,
[ParentChannelID] [int] NULL,
[Sequence] [int] NOT NULL,
[PanelIdx] [nvarchar](4000) NULL,
[Visible] [nvarchar](4000) NULL,
[FirstInserted] [datetime] NULL,
[LastUpdated] [datetime] NULL,
CONSTRAINT [PK$Channel] PRIMARY KEY CLUSTERED
([ChannelID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Channel] WITH CHECK ADD CONSTRAINT [FK$Channel$Channel] FOREIGN KEY([ParentChannelID])
REFERENCES [dbo].[Channel] ([ChannelID])
GO
ALTER TABLE [dbo].[Channel] CHECK CONSTRAINT [FK$Channel$Channel]
GO
ALTER TABLE [dbo].[Channel] WITH CHECK ADD CONSTRAINT [FK$Channel$Setup] FOREIGN KEY([SetupID])
REFERENCES [dbo].[Setup] ([SetupID])
GO
ALTER TABLE [dbo].[Channel] CHECK CONSTRAINT [FK$Channel$Setup]
GO
CREATE UNIQUE NONCLUSTERED INDEX [UQ$Channel$SetupID_Type] ON [dbo].[Channel]
([SetupID] ASC,[Type] ASC )
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
CREATE UNIQUE NONCLUSTERED INDEX [UQ$Channel$SetupID_ParentChannelID_Sequence] ON [dbo].[Channel]
([SetupID] ASC, [ParentChannelID] ASC, [Sequence] ASC )
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Variable](
[VariableID] [int] IDENTITY(1,1) NOT NULL,
[ChannelID] [int] NOT NULL,
[Key] [nvarchar](50) NOT NULL,
[Sequence] [int] NOT NULL,
[DefaultText] [nvarchar](4000) NULL,
[IONumber] [nvarchar](4000) NULL,
[LinkType] [nvarchar](4000) NULL,
[DataType] [nvarchar](4000) NULL,
[ImageTrue] [nvarchar](4000) NULL,
[ImageFalse] [nvarchar](4000) NULL,
[FormatString] [nvarchar](4000) NULL,
[GroupBoxIdx] [nvarchar](4000) NULL,
[ControlIdx] [nvarchar](4000) NULL,
[PlcVar] [nvarchar](4000) NULL,
[Value] [nvarchar](4000) NULL,
[DefaultValue] [nvarchar](4000) NULL,
[MinValue] [nvarchar](4000) NULL,
[MaxValue] [nvarchar](4000) NULL,
[Measure] [nvarchar](4000) NULL,
[KeyIdx] [nvarchar](4000) NULL,
[Behavior] [nvarchar](4000) NULL,
[TrueEnter] [nvarchar](4000) NULL,
[ShowCheckDigit] [nvarchar](4000) NULL,
[ShowOverflow] [nvarchar](4000) NULL,
[Visible] [nvarchar](4000) NULL,
[ReadOnly] [char](1) NULL,
[Dynamic] [char](1) NULL,
[FirstInserted] [datetime] NULL,
[LastUpdated] [datetime] NULL,
CONSTRAINT [PK$Variable] PRIMARY KEY CLUSTERED
([VariableID] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE UNIQUE NONCLUSTERED INDEX [UQ$Variable$ChannelID_Key] ON [dbo].[Variable]
([ChannelID] ASC, [Key] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
CREATE UNIQUE NONCLUSTERED INDEX [UQ$Variable$ChannelID_Sequence] ON [dbo].[Variable]
([ChannelID] ASC, [Sequence] ASC )
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Variable] WITH CHECK ADD CONSTRAINT [FK$Variable$Channel] FOREIGN KEY([ChannelID])
REFERENCES [dbo].[Channel] ([ChannelID])
GO
ALTER TABLE [dbo].[Variable] CHECK CONSTRAINT [FK$Variable$Channel]
GO
ALTER TABLE [dbo].[Variable] WITH CHECK ADD CONSTRAINT [CK$ChannelVariable$Dynamic_TF] CHECK (([Dynamic]='T' OR [Dynamic]='F'))
GO
ALTER TABLE [dbo].[Variable] CHECK CONSTRAINT [CK$ChannelVariable$Dynamic_TF]
GO
ALTER TABLE [dbo].[Variable] WITH CHECK ADD CONSTRAINT [CK$ChannelVariable$ReadOnly_TF] CHECK (([ReadOnly]='T' OR [ReadOnly]='F'))
GO
ALTER TABLE [dbo].[Variable] CHECK CONSTRAINT [CK$ChannelVariable$ReadOnly_TF]
GO
【问题讨论】:
-
你应该看看Entity Framework Code First。您可以共享您的 C# 模型并将其插入后端 MSSQL 数据库。您甚至可以使用现有的存储过程
-
您在前两段中描述的结构似乎一点也不复杂。你能分享你的设置、通道、属性和值的类代码吗?
-
我的意思是,插入/更新的过程听起来很复杂。结构或多或少很简单:设置 -> 通道 -> 变量。 (尽管 Channels 有层次结构)。
标签: c# sql-server object stored-procedures hierarchical