【问题标题】:Can LINQToSQL be used with sproc that uses sp_executeSQL? If not, how do you handle?LINQ To SQL 可以与使用 sp_executeSQL 的 sproc 一起使用吗?如果没有,你怎么处理?
【发布时间】:2009-07-08 15:55:01
【问题描述】:

LINQToSQL 不喜欢我的存储过程。它说存储过程的返回类型为“none”,这可能是因为我正在使用 sp_ExecuteSQL 语句来生成结果。

SQL Server Sproc 代码

我有一个类似于下面的存储过程
CREATE PROCEDURE Foo
@BarName varchar(50)
AS
BEGIN
DECLARE @SQL NVARCHAR(1024)
SET @SQL = 'SELECT tbFoo.FooID, tbFoo.Name FROM tbFOO ';
IF @BarName IS NOT NULL
BEGIN;
SET @SQL = @SQL
+ ' JOIN tbBar '
+ ' ON tbFoo.FooID = tbBar.FooID '
+ ' AND tbBar.BarName = ''' + @BarName + ''''
END;
EXEC sp_executeSQL @SQL
END

返回

这个存储过程返回一组 FooID | FooName 元组。

  • 12345 |探戈
  • 98765 |现金

目标

此存储过程将用于在搜索页面上返回搜索结果。这是一种相当常见的搜索模式。我想找到满足条件的 Foos,但是该条件正在应用于单独的表。我本可以选择不使用 sp_executeSQL 直接编写此查询,但是这种方法的作用是创建仅包含实际查询的表的 SQL。在现实世界的场景中,我可以有 12 个连接,而不是 1 个,这种方法只允许我将实际用作标准的连接串在一起。

问题

LINQ to SQL 不喜欢它。它说这个查询返回类型“none”并且不允许我指定返回类型。我不确定其他 ORM,例如 NHibernate、Entity Framework 或 LLBLGen 是否能够处理这个问题。到目前为止,LINQToSQL 在该项目上运行良好,我已经完成了 95% 的项目,并且不想为单个方法使用不同的 ORM。如果我进行进一步的更改,可能需要重构,但目前,我还没有准备好为此切换到不同的 ORM。

我真的很想找到一种方法在 LinqToSql 中完成这项工作!我不确定它是否可以。我还没有找到任何关于这个明显限制的官方文档。

目前我正在考虑的替代方案

到目前为止,我已经提出了一些替代方案。我不喜欢其中任何一个,所以我真的希望有人有一个很好的“hack”来解决这个问题。这些是我到目前为止所得到的:

  • 重写存储过程。摆脱 sp_executeSQL。对所有表执行 LEFT JOIN。
  • 使用 ADO.Net 手卷方法。
  • 不要使用存储过程,而是尝试在 LINQ 中进行所有过滤。

【问题讨论】:

    标签: linq-to-sql stored-procedures


    【解决方案1】:

    您可以使用 Linq2SQL 调用存储过程,但实体建模器可能无法为您生成调用包装器,因为它无法确定存储过程返回的内容,因此您必须自己创建调用包装器.

    为此,创建一个实体模型“非设计者”模块,其部分类定义与您的实体模型数据上下文(必要时还包括实体)匹配,并像这样定义调用包装器。

    namespace bar.Context
    {
        public partial class EntityModelDataContext
        {
            /// <summary>
            /// LINQ to SQL class mapper for Foo StoredProcedure
            /// </summary>
            /// <remarks>
            /// This one is too tough for the LINQ to SQL modeler tool to auto-generate
            /// </remarks>
            /// <returns></returns>
            [Function(Name = "dbo.Foo")]
            [ResultType(typeof(bar.Entity.tbFoo))]
            public ISingleresult<bar.Entity.tbFoo> Foo([Parameter(Name = "BarName", DbType = "varchar")] string barname)
            {
                IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), barname);
                return ((ISingleResult<bar.Entity.tbFoo>)(result.ReturnValue));
            }
        }
    }
    
    namespace bar.Entity
    {
        /// <summary>
        /// Data Modeler couldn't figure out how to generate this from the sproc
        /// hopefully your entity model generated this and you don't need to replicate it
        /// </summary>
        [Table(Name = "dbo.tbFoo")]
        public partial class tbFoo        {
           ....
        }
    }
    

    【讨论】:

    • 谢谢。这就是我一直在寻找的。现在我有了一个通用的解决方案来处理查询和返回结果的 UDF,其中 LINQ 不够聪明,无法推断数据类型,但我可以手动编写代码。
    【解决方案2】:

    是否有某些原因您无法使用 Linq 中的对象属性处理查询?

    我需要查看表架构,包括外键链接,以便举一个很好的例子,但它会是这样的:

    dbContextObject.Foos.Where(foo=> foo.Bars.Where(bar=> bar.BarName == searchString))
    

    然后,您将有一个 Foos 中的 IEnumerable 与条件匹配,您可以随心所欲地做任何事情。

    如果searchStringnull,那么您只需使用dbContextObject.Foos.All()

    【讨论】:

    • 在您的示例中,如果 searchString 为 NULL,LINQ 会做什么?
    • dbContextObject.Foos.Where(foo=> foo.Bars.Where(bar=> bar.BarName == searchString)) 真的有效吗?我收到一个错误无法将类型“System.Collections.Generic.IEnumerable”隐式转换为“bool”
    猜你喜欢
    • 2011-02-20
    • 2011-08-24
    • 2014-05-21
    • 2011-01-29
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多