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

前端之家收集整理的这篇文章主要介绍了.net – SqlMetal错误地生成我的存储过程的返回类型(LINQ)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
嗨有一个存储过程总是返回一行取决于一个参数:
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 Designer(在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 postthis MSDN article标题为“处理来自SPROC的多个结果形状”的部分都显示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 – 使用案例陈述:

这与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更改回其原始格式,但对返回的结果使用相同的别名.例如,我将OrderId和ProductId作为FakeId返回.

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作为FakeId来自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;
            }
        }
    }
}

您需要做的是将OrderId重命名为FakeId,将_OrderId重命名为_FakeId.完成后,您可以像往常一样使用上面的ISingleResult,例如:

int fakeId = dc.FakeODIds(i).Single().FakeId;

这就结束了我已经使用过并且能够在主题上找到的内容.

猜你在找的MsSQL相关文章