DRY CLR 表值函数

发布于 2024-11-16 14:33:12 字数 2474 浏览 1 评论 0原文

我正在使用 CLR 表值函数< /a> 到 SELECT 并返回使用许多变量的复杂数据库搜索的结果。

文档显示您以类似于以下的方式构建这样的函数:

public partial class UserDefinedFunctions
{
    private class ResultRow
    // This class holds a row which we want to return.
    {
        public SqlInt32 CustId;
        public SqlString Name;

        public ResultRow(SqlInt32 custId_, SqlString name_)
        {
            CustId = custId_;
            Name = name_;
        }
    }

    [SqlFunction(
        DataAccess = DataAccessKind.Read,
        FillRowMethodName = "Test_FillRow",
        TableDefinition = "CustId int" +
                          "Name nvarchar(50)")]
    public static IEnumerable Test()
    // This function contains the actual logic.
    {
        ArrayList results = new ArrayList();

        using (SqlConnection connection = new SqlConnection("context connection=true"))
        {
            connection.Open();

            using (SqlCommand select = new SqlCommand(
                "SELECT TOP 100 custid, name FROM Customers",
                connection))
            {
                using (SqlDataReader reader = select.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        results.Add(new ResultRow(
                            reader.GetSqlInt32(0),  // CustId
                            reader.GetSqlString(1)  // Name
                        ));
                    }
                }
            }
        }
        return results;
    }

    public static void Test_FillRow(
        object resultsObj,
        out SqlInt32 custid,
        out SqlString name)
    // This function takes a row and tells SQL Server what variables we want to 
    // return from it and what types it contains.
    {
        ResultRow selectResults = (ResultRow)resultsObj;

        custid = selectResults.CustId;
        name = selectResults.Name;
    }
}

问题是,它相当重复。首先,在 SqlFunction 块中定义表。然后,当您在返回的结果中添加或删除列时,您必须确保更新它以及

  • ResultRow 中的定义 ResultRow
  • 中构造函数的参数
  • ResultRow 中的赋值
  • 从 Test() 中的读取器获取的类型
  • Test_FillRow() 中的输出参数、
  • Test_FillRow() 中的赋值
  • 以及 SQL 查询本身,这是您真正要考虑的唯一部分。

我正在开发这样一个函数,它接受二十多个参数,返回更多行,并包含这八个可能出错的地方。 。所有的错误都很微不足道,很容易修复,但很容易犯这些错误,因为代码中有很多地方我必须手动保持同步。

这是违反DRY的,但我不知道如何消除重复。有没有更简洁的方法来编写 CLR 表值函数?

I'm using a CLR table-valued function to SELECT and return the results of a complex database search which uses many variables.

The documentation shows that you build such a function in a fashion similar to this:

public partial class UserDefinedFunctions
{
    private class ResultRow
    // This class holds a row which we want to return.
    {
        public SqlInt32 CustId;
        public SqlString Name;

        public ResultRow(SqlInt32 custId_, SqlString name_)
        {
            CustId = custId_;
            Name = name_;
        }
    }

    [SqlFunction(
        DataAccess = DataAccessKind.Read,
        FillRowMethodName = "Test_FillRow",
        TableDefinition = "CustId int" +
                          "Name nvarchar(50)")]
    public static IEnumerable Test()
    // This function contains the actual logic.
    {
        ArrayList results = new ArrayList();

        using (SqlConnection connection = new SqlConnection("context connection=true"))
        {
            connection.Open();

            using (SqlCommand select = new SqlCommand(
                "SELECT TOP 100 custid, name FROM Customers",
                connection))
            {
                using (SqlDataReader reader = select.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        results.Add(new ResultRow(
                            reader.GetSqlInt32(0),  // CustId
                            reader.GetSqlString(1)  // Name
                        ));
                    }
                }
            }
        }
        return results;
    }

    public static void Test_FillRow(
        object resultsObj,
        out SqlInt32 custid,
        out SqlString name)
    // This function takes a row and tells SQL Server what variables we want to 
    // return from it and what types it contains.
    {
        ResultRow selectResults = (ResultRow)resultsObj;

        custid = selectResults.CustId;
        name = selectResults.Name;
    }
}

The problem is, it's rather repetitive. First you define the table in the SqlFunction block. Then as you add or remove columns in the results you're returning, you have to make sure that you update it and

  • the definition in ResultRow
  • the arguments to the constructor in ResultRow
  • the assignment in ResultRow
  • the types grabbed from the reader in Test()
  • the out arguments in Test_FillRow()
  • the assignments in Test_FillRow()
  • and the SQL query itself, which is the only part you're really trying to think about to start with.

I'm working on such a function which takes over twenty arguments, returns even more rows, and contains these eight possible places to make mistakes. Eight. All the mistakes are trivial and easily fixed, but it's very easy to make them because there's so many places in the code which I have to manually keep in sync.

This is a violation of DRY, but I don't know how to eliminate the repetition. Is there a more concise way to write CLR table-valued functions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

青衫负雪 2024-11-23 14:33:12

如果将 ResultRow 替换为 object[],则可以使用 reader.GetValues(object[]) 并消除在 FillRow() 之前必须知道行中的内容,然后 FillRow 负责了解字段在原始查询。

这确实是一种权衡,你可以放弃一直使用强类型,以换取不必一直使用强类型,但很难两者兼顾:-)

If you replace your ResultRow with object[], you can use reader.GetValues(object[]) and eliminate having to know what's in the rows until FillRow(), and then FillRow is responsible for knowing what order the fields were in in the original query.

It's really a tradeoff, you can give up having strong typing all the way through, in exchange for not having to do strong typing all the way through, but it's hard to have it both ways :-)

温柔女人霸气范 2024-11-23 14:33:12

如果将参数集放入类中,则可以使用受其基类约束的通用方法来实现数据访问。我发现通常有一个类用于在组中传递参数,通常在其他地方以及重构时会发现有用。

将二十个参数传递给函数通常不是一个好主意。

这是我对函数参数普遍同意的一个很好的总结:
http://benbiddington.wordpress.com/2009/ 06/22/book-review-of-clean-code/

具体来说:

如果函数需要两个或三个以上的参数,则很可能
至少其中一些应该包含在自己的类中。

在这种情况下,这样做的好处可能是提取一些通用方法,帮助您更严格地遵守 DRY。

If you made your parameter sets into classes, you could use a generic method constrained on their base class to implement the data access. I've found generally a class used to pass parameters in groups like will usually find usefulness elsewhere as well as you refactor.

It's generally never a good idea to pass twenty parameters to a function.

Here's a good summary that I generally agree with on function arguments:
http://benbiddington.wordpress.com/2009/06/22/book-review-of-clean-code/

Specifically:

If a function expects more than two or three arguments, it’s likely
that at least some of those should be wrapped in their own class.

In this case, the benefit of this may likely be the extraction of some generic methods that will help you adhere more tightly to DRY.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文