T-SQL过程 - 过滤参数为Object/CLR/Xml/UDT

mel*_*dev 9 sql t-sql parameters filtering sql-server-2008

Cliffs:是否存在将标准"过滤器"类型传递给存储过程以封装stardate/enddate/pagesize/pagenum参数的已知模式?

不确定这个问题的正确位置.我正在探索将过滤对象参数传递给存储过程的想法,该存储过程封装了我们常用的过滤参数(startdate,enddate,pagenumber,pagesize,int的列表等).这样做的原因是减少了类似参数的数量以及围绕我们程序传播的样板SQL.这将从一开始就为每个程序提供更标准的界面和起点.我无法找到有关该主题的更多信息.

模式我注意到 - 当第一次构建大多数SP时,它们以where子句中使用的单个id参数开始.稍后,您可能需要为日期范围参数添加参数(startdate,enddate或dynamic range"ytd,mtd,dtd").如果数据集足够大,您还可能需要为服务器端分页引入pagesize/pagenum.一段时间后,您可能会发现需要结果来获取id的列表而不是单个id,因此您需要添加CSV或XML参数来包含ID.

最终,许多存储过程最终会有许多类似的样板和(希望)相同的参数来处理这些标准过滤参数.我正在尝试研究用于将封装的过滤器对象参数传递给我的过程的已知模式,理想情况下,它将在C#端强类型化.这在管理一组程序时特别有用,这些程序为所有需要相同过滤选项的报告提供动力(除了特定于报告的查询参数).

我的目标是减少WHERE子句所需的最小参数所需的参数数量,并创建一个标准机制,用于将通用过滤选项传递到过程中,并在过程内部使用这些值.如何通过XML或CLR或UDT参数实现这一目标?

对于这个问题的上下文,我通过C#2.0中的ADO.Net使用SQL Server 2008.不幸的是,LINQ/EF目前还不是这个项目的选项,我们必须坚持使用现有的RDBMS.如果存在需要改变技术的已知模式,我将有兴趣听到它.

编辑:感谢目前为止的回复.我已经为50分钟增加了一笔赏金,我会让它再跑几天,试图促进更多的讨论.如果我的问题不够明确,请发表评论..

ult*_*ife 5

我个人认为你是在过度思考或试图减少不需要减少的东西.您可能最好单独留下存储过程参数,或者尝试创建一些可以将一组参数附加到命令对象的基类和辅助函数.

然而,话虽这么说,我会在那里提出你的问题的解决方案,看看它是否符合你的需求:

我建议使用TSQL用户定义的类型.创建一个或多个类型.也许一个用于日期范围,一个用于分页和排序.我使用类似的过程将多行数据传递给存储过程.(有些代码可能需要稍微调整一下,因为我只修改了一些我已编写过的代码,并且在很长一段时间内我都没有使用过DataTable字段.)

最终,所有这些都缩短了应用程序方法中的参数列表并匹配了存储过程.存储过程将负责提取或加入表变量中的信息.下面列出的类确实能够在.NET应用程序端保持这些参数的强类型.

if not exists (select * from INFORMATION_SCHEMA.DOMAINS where DOMAIN_SCHEMA = 'dbo' and DOMAIN_NAME = 'DateRange' and DATA_TYPE = 'table type')
begin

    create type dbo.DateRange as table 
    (
        StartDate datetime2 null
        ,EndDate datetime2 null
    )

end
go


if not exists (select * from INFORMATION_SCHEMA.DOMAINS where DOMAIN_SCHEMA = 'dbo' and DOMAIN_NAME = 'Paging' and DATA_TYPE = 'table type')
begin

    create type dbo.Paging as table 
    (
        PageNumber int null
        ,PageSize int null
        ,SortField sysname null
        ,SortDirection varchar(4) null
    )

end
go
Run Code Online (Sandbox Code Playgroud)

SQL用户定义的类型可以表示为.NET应用程序中的强类型对象.从基类开始:

    Imports System
    Imports System.Data
    Imports System.Data.SqlClient
    Imports System.Runtime.Serialization


    Namespace SqlTypes

        <Serializable()> _
        <System.ComponentModel.DesignerCategory("Code")> _
        Public MustInherit Class SqlTableTypeBase
            Inherits DataTable

            Public Sub New()

                MyBase.New()
                Initialize()

            End Sub


            Public Sub New(ByVal tableName As String)

                MyBase.New(tableName)
                Initialize()

            End Sub


            Public Sub New(ByVal tableName As String, ByVal tableNamespace As String)

                MyBase.New(tableName, tableNamespace)
                Initialize()

            End Sub


            Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)

                MyBase.New(info, context)

            End Sub


            ''' <summary>
            ''' Implement this method to create the columns in the data table to match the SQL server user defined table type
            ''' </summary>
            ''' <remarks></remarks>
            Protected MustOverride Sub Initialize()


            Public Function CreateParameter(parameterName As String) As SqlParameter

                Dim p As New SqlParameter(parameterName, SqlDbType.Structured)
                p.Value = Me

                Return p

            End Function

        End Class

    End Namespace
Run Code Online (Sandbox Code Playgroud)

为SQL类型创建实现:

Imports System
Imports System.Data
Imports System.Runtime.Serialization


Namespace SqlTypes

    <Serializable()> _
    <System.ComponentModel.DesignerCategory("Code")> _
    Public Class DateRange
        Inherits SqlTableTypeBase

        Public Sub New()

            MyBase.New()

        End Sub


        Public Sub New(ByVal tableName As String)

            MyBase.New(tableName)

        End Sub


        Public Sub New(ByVal tableName As String, ByVal tableNamespace As String)

            MyBase.New(tableName, tableNamespace)

        End Sub


        Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)

            MyBase.New(info, context)

        End Sub


        'TODO: throw some more overloaded constructors in here...

        Public Sub New(startDate As DateTime?, endDate As DateTime?)

            MyBase.New()

            Me.StartDate = startDate
            Me.EndDate = endDate

        End Sub


        Public Property StartDate As DateTime?
            Get
                Return CType(Me.Rows(0)(0), DateTime?)
            End Get
            Set(value As DateTime?)
                Me.Rows(0)(0) = value
            End Set
        End Property


        Public Property EndDate As DateTime?
            Get
                Return CType(Me.Rows(0)(1), DateTime?)
            End Get
            Set(value As DateTime?)
                Me.Rows(0)(1) = value
            End Set
        End Property


        Protected Overrides Sub Initialize()

            Me.Columns.Add(New DataColumn("StartDate", GetType(DateTime?)))
            Me.Columns.Add(New DataColumn("EndDate", GetType(DateTime?)))

            Me.Rows.Add({Nothing, Nothing})

        End Sub

    End Class

End Namespace
Run Code Online (Sandbox Code Playgroud)

和:

Imports System
Imports System.Data
Imports System.Runtime.Serialization


Namespace SqlTypes

    <Serializable()> _
    <System.ComponentModel.DesignerCategory("Code")> _
    Public Class Paging
        Inherits SqlTableTypeBase

        Public Sub New()

            MyBase.New()

        End Sub


        Public Sub New(ByVal tableName As String)

            MyBase.New(tableName)

        End Sub


        Public Sub New(ByVal tableName As String, ByVal tableNamespace As String)

            MyBase.New(tableName, tableNamespace)

        End Sub


        Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)

            MyBase.New(info, context)

        End Sub


        'TODO: throw some more overloaded constructors in here...


        Public Sub New(pageNumber As Integer?, pageSize As Integer?)

            MyBase.New()

            Me.PageNumber = pageNumber
            Me.PageSize = pageSize

        End Sub


        Public Sub New(sortField As String, sortDirection As String)

            MyBase.New()

            Me.SortField = sortField
            Me.SortDirection = sortDirection

        End Sub


        Public Sub New(pageNumber As Integer?, pageSize As Integer?, sortField As String, sortDirection As String)

            Me.New(pageNumber, pageSize)

            Me.SortField = sortField
            Me.SortDirection = sortDirection

        End Sub


        Public Property PageNumber As Integer?
            Get
                Return CType(Me.Rows(0)(0), Integer?)
            End Get
            Set(value As Integer?)
                Me.Rows(0)(0) = value
            End Set
        End Property


        Public Property PageSize As Integer?
            Get
                Return CType(Me.Rows(0)(1), Integer?)
            End Get
            Set(value As Integer?)
                Me.Rows(0)(1) = value
            End Set
        End Property


        Public Property SortField As String
            Get
                Return CType(Me.Rows(0)(2), String)
            End Get
            Set(value As String)
                Me.Rows(0)(2) = value
            End Set
        End Property


        Public Property SortDirection As String
            Get
                Return CType(Me.Rows(0)(3), String)
            End Get
            Set(value As String)
                Me.Rows(0)(3) = value
            End Set
        End Property


        Protected Overrides Sub Initialize()

            Me.Columns.Add(New DataColumn("PageNumber", GetType(Integer?)))
            Me.Columns.Add(New DataColumn("PageSize", GetType(Integer?)))
            Me.Columns.Add(New DataColumn("SortField", GetType(String)))
            Me.Columns.Add(New DataColumn("SortDirection", GetType(String)))

            Me.Rows.Add({Nothing, Nothing, Nothing, Nothing})

        End Sub

    End Class

End Namespace
Run Code Online (Sandbox Code Playgroud)

实例化对象并在构造函数中设置值,然后只需从对象中获取参数,并将其附加到存储过程命令对象的参数集合中.

cmd.Parameters.Add(New DateRange(startDate, endDate).CreateParameter("DateRangeParams"))
cmd.Parameters.Add(New Paging(pageNumber, pageSize).CreateParameter("PagingParams"))
Run Code Online (Sandbox Code Playgroud)

编辑 由于这个答案围绕着强类型,我想我应该在方法签名中添加一个强类型的例子:

'method signature with UDTs
Public Function GetMyReport(customParam1 as Integer, timeFrame as DateRange, pages as Paging) as IDataReader

'method signature without UDTs
Public Function GetMyReport(customParam1 as Integer, startDate as DateTime, endDate as DateTime, pageNumber as Integer, pageSize as Integer)
Run Code Online (Sandbox Code Playgroud)