【问题标题】:LINQ-to-SQL: Stored Procedure that returns a single scalar value?LINQ-to-SQL:返回单个标量值的存储过程?
【发布时间】:2008-11-13 14:43:35
【问题描述】:

我正在将 LINQ-to-SQL 用于查询旧数据库的应用程序。我需要调用一个存储过程,它选择一个整数值。更改存储过程不是一种选择。

设计者用这个签名创建一个方法:

private ISingleResult<sp_xal_seqnoResult> NextRowNumber([Parameter(DbType="Int")] System.Nullable<int> increment, [Parameter(DbType="Char(3)")] string dataset)

我希望返回类型为 int。如何使用 LINQ-to-SQL 做到这一点?

【问题讨论】:

    标签: c# linq-to-sql


    【解决方案1】:

    对于标量函数 (UDF) 而不是 SP,这将是微不足道的。但是,它应该很容易工作 - 尽管如果 SP 很复杂(即 FMT_ONLY 无法 100% 检查它),那么您可能需要“帮助”它...

    这是我从返回整数的简化 SP 生成的一些 dbml;您可以通过“使用... xml 编辑器打开”来编辑 dbml:

    <Function Name="dbo.foo" Method="foo">
        <Parameter Name="inc" Type="System.Int32" DbType="Int" />
        <Parameter Name="dataset" Type="System.String" DbType="VarChar(20)" />
        <Return Type="System.Int32" />
    </Function>
    

    (请注意,您显然需要调整名称和数据类型)。

    这里是生成的 C#:

    [Function(Name="dbo.foo")]
    public int foo([Parameter(DbType="Int")] System.Nullable<int> inc, [Parameter(DbType="VarChar(20)")] string dataset)
    {
        IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), inc, dataset);
        return ((int)(result.ReturnValue));
    }
    

    如果您当前的 SP 使用 SELECT(而不是 RETURN),则 DBML 将需要反映这一点。您可以通过隐藏实现细节并在部分类中提供公共包装器来解决此问题;例如:

    <Function Name="dbo.foo" Method="FooPrivate" AccessModifier="Private">
        <Parameter Name="inc" Type="System.Int32" DbType="Int" />
        <Parameter Name="dataset" Type="System.String" DbType="VarChar(20)" />
        <ElementType Name="fooResult" AccessModifier="Internal">
          <Column Name="value" Type="System.Int32" DbType="Int NOT NULL" CanBeNull="false" />
        </ElementType>
    </Function>
    

    上面描述了一个SP,它返回一个单列的单表;但我已将 SP 设为数据上下文的“私有”,并将结果类型设为程序集的“内部”(隐藏它):

    [Function(Name="dbo.foo")]
    private ISingleResult<fooResult> FooPrivate(
        [Parameter(DbType="Int")] System.Nullable<int> inc,
        [Parameter(DbType="VarChar(20)")] string dataset)
    {
        IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), inc, dataset);
        return ((ISingleResult<fooResult>)(result.ReturnValue));
    }
    

    现在在我自己的类文件中我可以在正确的命名空间中添加一个新的部分类(一个新的 .cs 文件),这样可以更方便地公开该方法:

    namespace MyNamespace {
        partial class MyDataContext
        {
            public int Foo(int? inc, string dataSet)
            {
                return FooPrivate(inc, dataSet).Single().value;
            }
        }
    }
    

    (命名空间和上下文名称需要与实际的数据上下文相同)。这添加了一个公共方法,该方法向调用者隐藏蹩脚的细节。

    不要直接编辑designer.cs文件;您的更改将丢失。只编辑 dbml 或部分类。

    【讨论】:

    • @driss - 如果您遇到 SELECT 问题,请告诉我
    • 我早些时候在我的项目中使用了相同的技术。它工作得很好.. 直到你以某种方式在编辑器中编辑你的 DBML。您的所有更改都将被覆盖。每次手动修改时,我都会保留一个单独的 xml 文件,但我希望有更好的方法。
    • @boris:哪种技术?你在编辑 .designer.cs 吗?不要那样做...向部分类添加方法(我将添加一个示例)
    • 程序使用SELECT。您的方法起初似乎有效,但我刚刚发现 value 字段始终为 0,无论实际结果如何。这可能与选择的列未命名有关吗?我可以在 dbml 中指定,该值是第一行的第一列吗?
    • @driis - 2 分钟,我会调查
    【解决方案2】:

    RETURN @VALUE 作为 proc 的最后一条语句。

    然后它将自动检测类型 int、string、bool 等并相应地生成包装方法。

    【讨论】:

    • +1 返回值必须来自标量变量,因此 RETURN SELECT COUNT(*) FROM table 和 1RETURN SELECT @Value = COUNT(*) FROM table1 将不起作用,但 RETURN @Value 将起作用。此外,MS SQL/LINQ to SQL 似乎不支持 tinyint/byte 返回类型。
    【解决方案3】:

    如果您在 Linq to SQL 类项目中使用 Visual Studio 的 .xsd 文件,请确保:

    1. 右键单击适配器中的存储过程或函数调用。
    2. 选择属性
    3. 将执行模式更改为标量

    这将使您的适配器函数返回类型为“对象”。然后,您需要将其转换为 int 或 string,或者它应该是的任何类型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多