Mik*_*ier 6 .net linq sql-server stored-procedures sqlmetal
嗨有一个存储过程总是返回一行取决于一个参数:
IF @bleh = 1
SELECT TOP 1 Xyz FROM Abc
ELSE
SELECT TOP 1 Def FROM Abc
Run Code Online (Sandbox Code Playgroud)
我必须使用SqlMetal生成DataContext但该存储过程返回IMultipleResults一个错误.相反它应该返回ISingleResult...
如果我删除if(发出单个SELECT调用),ISingleResult则会生成返回类型.
有任何想法吗?
Ahm*_*eed 10
您描述的场景是设计的.我已经使用.NET 3.5和.NET 4.0 Beta 2进行了测试,并得到了相同的结果.给定一个使用IF/ELSE结构的SPROC,生成的结果和使用的工具是:
设计器无法识别具有多个返回值的存储过程,并将它们全部映射为返回单个整数.
SQLMetal命令行工具确实识别多个结果,并将正确输入方法作为IMultipleResults.您可以使用SQLMetal或手动修改DBML,也可以将此存储过程的方法签名添加到您自己的DataContext的分部类中.
在这篇博文中, Dinesh Kulkarni评论了相反的情况,即设计师不添加IMultipleResults并使用ISingleResult.他说(重点补充):
不,设计师不支持此功能.因此,您必须在分部类中添加该方法.但是,SqlMetal会提取sproc.原因是实现细节:两者使用相同的代码生成器但使用不同的数据库模式提取器.
此外,Scott Gu的文章和MSDN文章中标题为"处理来自SPROC的多个结果形状"的部分都显示IMultipleResults与使用相同结构的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
Run Code Online (Sandbox Code Playgroud)
显然,类型需要相似或者可以投射到另一个类型.例如,如果一个是a INT而另一个是a DECIMAL(8, 2),则使用小数来保持精度.
重写#2 - 使用案例陈述:
这与马克的建议完全相同.
SELECT TOP 1 CASE WHEN @Input = 1 THEN OrderId ELSE ProductId END FROM OrderDetails
Run Code Online (Sandbox Code Playgroud)
您可以使用标量值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
Run Code Online (Sandbox Code Playgroud)
这可行,但比以前的选项更乏味.此外,将来使用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));
}
Run Code Online (Sandbox Code Playgroud)
3)将您的SPROC更改回其原始格式,但对返回的结果使用相同的别名.例如,我将返回两者 OrderId和ProductIdas 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
Run Code Online (Sandbox Code Playgroud)
注意我这里没有使用变量,而是直接使用您最初使用的格式.
4)由于我们使用的是FakeId别名,我们需要调整生成的代码.如果您导航到在步骤2中为您生成的映射类(FakeODIdsResult在我的例子中).OrderId在我的例子中,该类将使用代码中步骤1的原始列名.事实上,如果步骤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;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
你需要做的是重新命名OrderId,以FakeId及_OrderId对_FakeId.完成后,您可以像往常一样使用上面的ISingleResult,例如:
int fakeId = dc.FakeODIds(i).Single().FakeId;
Run Code Online (Sandbox Code Playgroud)
这就结束了我已经使用过并且能够在主题上找到的内容.
| 归档时间: |
|
| 查看次数: |
2303 次 |
| 最近记录: |