gpt4 book ai didi

.net - SqlMetal 错误地生成了我的存储过程 (LINQ) 的返回类型

转载 作者:行者123 更新时间:2023-12-03 13:55:59 25 4
gpt4 key购买 nike

嗨,有一个存储过程,它总是根据参数返回单行:

IF @bleh = 1
SELECT TOP 1 Xyz FROM Abc
ELSE
SELECT TOP 1 Def FROM Abc

我必须使用 SqlMetal 来生成 DataContext 但这个存储过程返回一个 IMultipleResults ,这是一个错误。相反,它应该返回 ISingleResult ...

如果我删除 if(放置一个 SELECT 调用),一个 ISingleResult生成返回类型。

有任何想法吗?

最佳答案

您描述的场景是设计使然。我已经对 .NET 3.5 和 .NET 4.0 Beta 2 进行了测试,并得到了相同的结果。给定一个使用 IF/ELSE 结构的 SPROC,生成的结果和使用的工具是:

  • SqlMetal : IMultipleResults
  • LINQ To SQL 设计器 (在 VS IDE 中拖放):ISingleResult

  • 这是 supported by Matt Warren在微软:

    The designer does not recognize stored procs with multiple return values and will map them all to returning a single integer.

    SQLMetal command line tool does recognize the multiple results and will type the return of the method correctly as IMultipleResults. You can either use SQLMetal or modify the DBML by hand or add the method signature for this stored proc to your own partial class for your DataContext.



    this blog post Dinesh Kulkarni 评论相反的场景,即设计者不添加 IMultipleResults 而是使用 ISingleResult。他说(强调):

    And no, the designer does not support this feature. So you have to add the method in your partial class. SqlMetal does however extract the sproc. The reason for that is an implementation detail: the two use the same code generator but different database schema extractors.



    此外, Scott Gu's post 中标题为“处理来自 SPROC 的多个结果形状”的部分和 this MSDN article两者都显示 IMultipleResults 与使用相同结构的 SPROC 一起使用。

    太好了,现在呢?有一些解决方法,有些比其他方法更好。

    重写 SPROC

    您可以重写 SPROC,以便 SqlMetal 使用 ISingleResult 生成函数。这可以通过

    重写 #1 - 将结果存储在变量中:
    DECLARE @Result INT
    IF @Input = 1
    SET @Result = (SELECT TOP 1 OrderId FROM OrderDetails)
    ELSE
    SET @Result = (SELECT TOP 1 ProductId FROM OrderDetails ORDER BY ProductId DESC)

    SELECT @Result As Result

    显然,这些类型需要相似或可以转换为其他类型。例如,如果一个是 INT另一个是 DECIMAL(8, 2)您将使用小数来保持精度。

    重写 #2 - 使用 case 语句:

    这与 Mark's suggestion 相同.
    SELECT TOP 1 CASE WHEN @Input = 1 THEN OrderId ELSE ProductId END FROM OrderDetails

    使用 UDF 而不是 SPROC

    您可以使用 scalar-valued UDF并调整您的查询以使用 UDF 格式(与上述变量方法相同)。 SqlMetal 将为它生成一个 ISingleResult,因为只返回一个值。
    CREATE FUNCTION [dbo].[fnODIds] 
    (
    @Input INT
    )
    RETURNS INT
    AS
    BEGIN
    DECLARE @Result INT

    IF @Input = 1
    SET @Result = (SELECT TOP 1 UnitPrice FROM OrderDetails)
    ELSE
    SET @Result = (SELECT TOP 1 Quantity FROM OrderDetails ORDER BY Quantity DESC)

    RETURN @Result

    END

    伪造 SPROC 并将其关闭

    这有效,但比以前的选项更乏味。此外,将来使用 SqlMetal 将覆盖这些更改并需要重复该过程。使用部分类并将相关代码移到那里将有助于防止这种情况。

    1) 更改您的 SPROC 以返回单个 SELECT语句(注释掉您的实际代码),例如 SELECT TOP 1 OrderId FROM OrderDetails
    2)使用SqlMetal。它将生成一个 ISingleResult:
    [Function(Name = "dbo.FakeODIds")]
    public ISingleResult<FakeODIdsResult> FakeODIds([Parameter(Name = "Input", DbType = "Int")] System.Nullable<int> input)
    {
    IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), input);
    return ((ISingleResult<FakeODIdsResult>)(result.ReturnValue));
    }

    3) 将您的 SPROC 改回其原始形式,但对返回的结果使用相同的别名。例如,我将同时返回 OrderIdProductIdFakeId .
    IF @Input = 1
    SELECT TOP 1 OrderId As FakeId FROM OrderDetails
    ELSE
    SELECT TOP 1 Quantity As FakeId FROM OrderDetails ORDER BY Quantity DESC

    请注意,我在这里没有使用变量,而是使用您最初直接使用的格式。

    4) 由于我们使用了 FakeId 别名,我们需要调整生成的代码。如果您导航到在步骤 2 中为您生成的映射类(在我的情况下为 FakeODIdsResult)。该类将使用代码中第 1 步中的原始列名, OrderId就我而言。事实上,如果步骤 1 中的语句以别名开头,即可以避免整个步骤。 SELECT TOP 1 OrderId As FakeId FROM OrderDetails .如果你没有,你需要进入并调整一些东西。

    FakeODIdsResult 将使用 OrderId ,它不会返回任何内容,因为它别名 FakeId .它看起来类似于:
    public partial class FakeODIdsResult
    {
    private System.Nullable<int> _OrderId;

    public FakeODIdsResult()
    {
    }

    [Column(Storage = "_OrderId", DbType = "Int")]
    public System.Nullable<int> OrderId
    {
    get
    {
    return this._OrderId;
    }
    set
    {
    if ((this._OrderId != value))
    {
    this._OrderId = value;
    }
    }
    }
    }

    您需要做的是重命名 OrderIdFakeId_OrderId_FakeId .完成后,您可以像往常一样使用上面的 ISingleResult,例如:
    int fakeId = dc.FakeODIds(i).Single().FakeId;

    这总结了我使用过的并且能够在该主题上找到的内容。

    关于.net - SqlMetal 错误地生成了我的存储过程 (LINQ) 的返回类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2037280/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com