【问题标题】:Passing List of Custom object to SQL Server Stored Procedure将自定义对象列表传递给 SQL Server 存储过程
【发布时间】:2014-08-15 20:32:06
【问题描述】:

我希望通过一个存储过程调用来传递自定义对象列表。这是对象

 public class OGFormResponse
{
    public string Response {get; set;}
    public OGFormLabelVO FormLabel {get; set;}
}
    public class OGFormLabelVO
{
    public int OGFormLabelKey {get; set;}
    public string FormType {get; set;}
    public string LabelText {get; set;}
    public string ControlName {get; set;}
    public string DisplayStatus {get; set;}
    public string LabelType = {get; set;}
    public bool IsActive {get; set;}
    public string LabelParentControlName {get; set;}
}

这是数据库关系

CREATE TABLE [dbo].[OGFormLabels](
[OGFormLabelKey] [int] IDENTITY(1,1) NOT NULL,
[OGFLText] [nvarchar](max) NULL,
[OGFLControlName] [nvarchar](50) NOT NULL,
[OGFLIsActive] [bit] NOT NULL,
[OGFLDisplayStatusKey] [int] NOT NULL,
[OGFLFormTypeKey] [int] NOT NULL,
[OGFLLabelTypeKey] [int] NOT NULL,
[OGFLParentKey] [int] NULL,
[OGFLBeginDate] [datetime] NOT NULL,
[OGFLBeginUser] [varchar](40) NOT NULL,
[OGFLUpdateDate] [datetime] NOT NULL,
[OGFLUpdateUser] [varchar](40) NOT NULL,
CONSTRAINT [PK_OGFormLabel] PRIMARY KEY CLUSTERED 
(
[OGFormLabelKey] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,       ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[OGFormLabels] ADD  CONSTRAINT [DF_OGFormLabel_OGFLBeginDate]  DEFAULT (getdate()) FOR [OGFLBeginDate]
GO

ALTER TABLE [dbo].[OGFormLabels] ADD  CONSTRAINT [DF_OGFormLabel_OGFLBeginUser]  DEFAULT ('dbo') FOR [OGFLBeginUser]
GO

ALTER TABLE [dbo].[OGFormLabels] ADD  CONSTRAINT [DF_OGFormLabel_OGFLUpdateDate]  DEFAULT (getdate()) FOR [OGFLUpdateDate]
GO

ALTER TABLE [dbo].[OGFormLabels] ADD  CONSTRAINT [DF_OGFormLabel_OGFLUpdateUser]  DEFAULT ('dbo') FOR [OGFLUpdateUser]
GO

ALTER TABLE [dbo].[OGFormLabels]  WITH CHECK ADD  CONSTRAINT [FK_OGFormLabel_OGFormStatus] FOREIGN KEY([OGFLFormTypeKey])
REFERENCES [dbo].[OGDisplayStatus] ([OGDisplayStatusKey])
GO

ALTER TABLE [dbo].[OGFormLabels] CHECK CONSTRAINT [FK_OGFormLabel_OGFormStatus]
GO

ALTER TABLE [dbo].[OGFormLabels]  WITH CHECK ADD  CONSTRAINT [FK_OGFormLabel_OGFormType] FOREIGN KEY([OGFLFormTypeKey])
REFERENCES [dbo].[OGFormType] ([OGFormTypeKey])
GO

ALTER TABLE [dbo].[OGFormLabels] CHECK CONSTRAINT [FK_OGFormLabel_OGFormType]
GO

ALTER TABLE [dbo].[OGFormLabels]  WITH CHECK ADD  CONSTRAINT [FK_OGFormLabel_OGLabelType] FOREIGN KEY([OGFLLabelTypeKey])
REFERENCES [dbo].[OGLabelType] ([OGLabelTypeKey])
GO

ALTER TABLE [dbo].[OGFormLabels] CHECK CONSTRAINT [FK_OGFormLabel_OGLabelType]
GO


CREATE TABLE [dbo].[OGFormResponses](
[OGFormResponseKey] [int] IDENTITY(1,1) NOT NULL,
[OGRFormKey] [int] NOT NULL,
[OGRFormLabelKey] [int] NOT NULL,
[OGRResponse] [nvarchar](max) NOT NULL,
[OGRBeginDate] [datetime] NOT NULL,
[OGRBeginUser] [varchar](40) NOT NULL,
[OGRUpdateDate] [datetime] NOT NULL,
[OGRUpdateUser] [varchar](40) NOT NULL,
CONSTRAINT [PK_OGFormResponse] PRIMARY KEY CLUSTERED 
(
[OGFormResponseKey] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[OGFormResponses] ADD  CONSTRAINT [DF_OGFormResponse_OGRBeginDate]  DEFAULT (getdate()) FOR [OGRBeginDate]
GO

ALTER TABLE [dbo].[OGFormResponses] ADD  CONSTRAINT [DF_OGFormResponse_OGRBeginUser]  DEFAULT ('dbo') FOR [OGRBeginUser]
GO

ALTER TABLE [dbo].[OGFormResponses] ADD  CONSTRAINT [DF_OGFormResponse_OGRUpdateDate]  DEFAULT (getdate()) FOR [OGRUpdateDate]
GO

ALTER TABLE [dbo].[OGFormResponses] ADD  CONSTRAINT [DF_OGFormResponse_OGRUpdateUser]  DEFAULT ('dbo') FOR [OGRUpdateUser]
GO

ALTER TABLE [dbo].[OGFormResponses]  WITH CHECK ADD  CONSTRAINT [FK_OGFormResponse_OGForm] FOREIGN KEY([OGRFormKey])
REFERENCES [dbo].[OGForm] ([OGFormKey])
GO

ALTER TABLE [dbo].[OGFormResponses] CHECK CONSTRAINT [FK_OGFormResponse_OGForm]
GO

ALTER TABLE [dbo].[OGFormResponses]  WITH CHECK ADD  CONSTRAINT [FK_OGFormResponse_OGFormLabel] FOREIGN KEY([OGRFormLabelKey])
REFERENCES [dbo].[OGFormLabels] ([OGFormLabelKey])
GO

ALTER TABLE [dbo].[OGFormResponses] CHECK CONSTRAINT [FK_OGFormResponse_OGFormLabel]
GO

所以基本上,OGFormResponseVO 与 OGFormLabelVO 是一对一的关系。我希望能够通过存储过程调用将 OGFormResponseVO 列表插入数据库。我研究了表值参数,您不能将类型的列设为另一种类型。是否有解决方法,或者我最好将子对象的所有属性作为单独的参数传递,或者有更好的方法。我必须使用 SP,因为它是更大项目的一部分,因此其他数据模型选项不可用。

【问题讨论】:

  • OGFormResponse 和 OGFormLabelVO 是否存储在同一个表中?分开表?如果是单独的表,关系是如何定义的?关键约束?公共领域?
  • 查看 ADO.NET 结构化参数。您需要在数据库中为它们定义相应的表类型。 Dapper 在最新版本中也支持它们。
  • @Brandon 它们是带有键约束的单独表,我已经添加了 DDL
  • @IsaacLevin:更多细节让你开始here
  • @MarcelN。谢谢你的链接,我去看看。 4.0 和 4.5 之间有什么明显的区别吗?我的应用是 4.0

标签: c# sql sql-server stored-procedures table-valued-parameters


【解决方案1】:

正如我在 cmets 中所说,您可以使用 structured parameters 执行此操作。

您只需要稍微重新建模,以便将它们映射到表值参数(以DataTables 开头)。

假设你想同时插入表单标签和相关响应,你需要定义它们之间的临时关系。另外,注意到表格比模型有更多的列,所以我认为你缩小了最初的例子。

OGFormResponse类对应的结构化参数需要有以下字段:

CREATE TYPE [dbo].[OGFormResponse] AS TABLE(
  [Response] VARCHAR(256),
  [SequenceId] INT --This is just a temporary sequence (1..N) you can use to map to form labels (see below)
)

OGFormLabelVO 的表值类型可以 1:1 映射到 C# 类,外加一列 - SequenceId

SP 可能看起来像这样:

CREATE PROCEDURE [dbo].[SaveFormStuff] 
    @FormResponses AS [dbo].[OGFormResponse] READONLY,
    @FormLabels AS [dbo].[OGFormLabelVO] READONLY
AS

   SET NOCOUNT ON;

   //This stores the PKs of the inserted form labels
   DECLARE @InsertedFormLabels AS TABLE ( 
     Id INT NOT NULL,
     SequenceId INT NOT NULL
   )

   INSERT INTO [dbo].[OGFormLabels]
     (...)
   SELECT (...) 
   FROM @FormLabels FL
   OUTPUT inserted.OGFormLabelKey, FL.SequenceId INTO @InsertedFormLabels

   -- Now you have the newly inserted form label ID mapped to sequence IDs
   -- Time to insert responses 

   INSERT INTO [dbo].[OGFormResponses]
     (...)
   SELECT (...), 
          OGRFormLabelKey = IFL.Id 
   FROM @FormResponses FR
   INNER JOIN @InsertedFormLabels IFL
     ON IFL.SequenceId = FR.SequenceId  
END

【讨论】:

  • 如果我没有使用平板电脑,我会说的正是这样 :-) +1
  • 要添加到这一点,您可以在 c# 中使用 SqlMetadata 数组声明类型,然后从中构建 SqlDataRecord 列表并在列表上使用 AsEnumerable() 传递它(如果您不想使用数据表)
  • @john:是的,我认为这是 Dapper 默认使用的。另一种选择是使用DataTables。无论如何,尝试更多地关注 SQL 部分。
猜你喜欢
  • 2014-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-20
  • 2014-08-29
相关资源
最近更新 更多