如何创建一个支持转换为sql的方法?

时间:2010-10-05 15:42:16

标签: c# .net linq linq-to-sql .net-4.0

我想使用我在查询中创建的方法,因为我需要实现一种特殊类型的过滤器...

return manager.Clients.SelectAll().Where(cli => cli.Name.SatisfyFilter(filter.Name) && cli.LastName.SatisfyFilter(filter.LastName) && cli.MiddleName.SatisfyFilter(filter.MiddleName)).ToList();

但我明白了:

“Method”Boolean SatisfyFilter(System.String,System.String)'没有支持的SQL转换。“

错误

我的方法是:

public static bool SatisfyFilter(this string palavra, string filtro)

相同
public bool Contains(string value)

在字符串类型中,而Contains工作得很好......

我需要这个方法在IQueryable上运行,因为我的表有2500万个客户......

我在sql profiler上看到包含在sql中转换...

如何实现我的方法将相关的过滤器代码发送到sql? = /

6 个答案:

答案 0 :(得分:8)

在SQL服务器上创建一个与C#代码等效的用户函数。说它被称为“dbo.SatsFilter”。

在datacontext覆盖上创建一个方法,如下所示:

public bool SatisfiesFilter(string name, string filter)
{
  // some sort of implementation.
}

使用[Function][Parameter]属性装饰C#方法,使其看起来像:

[Function(Name="dbo.SatsFilter",IsComposable=true)]
public bool SatisfiesFilter([Parameter name="@name",DbType="nvarchar(50)"]string name, [Parameter name="@filter",DbType="nvarchar(50)"]string filter)

IsComposable=true表示它是一个函数而不是存储过程,因此可以用作更大查询的一部分。

您现在可以使用DataContext的这种方法,并在适当时将其转换为SQL,或者在内存中执行的查询中使用C#。

另请注意,如果您只想一直使用SQL(有时很有用),则可以在C#代码中调用方法时调用SQL:

[Function(Name="dbo.SatsFilter",IsComposable=true)]
public bool SatisfiesFilter([Parameter name="@name",DbType="nvarchar(50)"]string name, [Parameter name="@filter",DbType="nvarchar(50)"]string filter)
{
  return (bool)ExecuteMethodCall(this, (MethodInfo)MethodInfo.GetCurrentMethod(), name, filter).ReturnValue;
}

当C#等价物方便时,这不是很有用,因为它意味着对数据库的命中和一些翻译,但是如果用户函数依赖于数据库状态或很难很好地转换为C#

答案 1 :(得分:4)

一个简单的答案是你不能。 LINQ to SQL转换器只识别一些标准的.NET方法,你无法添加其他方法。

  • 如果你需要这样的东西,你需要明确地创建表达式树(用作lambda表达式的主体)。这样做的直接方法是使用Expression类的方法,但它可以简化很多。

  • 也许最好的选择是使用LINQKit project。它可以调用其他 lambda表达式(不是很方法,但是关闭)。它提供了AsExpandable扩展方法,允许您编写:

    Expression<Func<Purchase, bool>> customFunction = ...
    var data = new MyDataContext();
    var query =
      from c in data.Purchases.AsExpandable()
      where customFunction.Compile()(c)
      select c.Name;
    

    customFunction是一个编译为表达式树的lambda函数,您可以在查询中使用它。 AsExpandable扩展名替换了函数体的用法,因此LINQ to SQL转换器可以处理这个问题。您可以在my blog post中详细了解其工作原理。

  • 其他人讨论的其他替代方案是将功能实现为SQL用户定义的函数。然后,您可以将函数拖动到数据上下文并从查询中调用该函数。翻译人员只需插入对SQL函数的调用。

答案 2 :(得分:1)

如果您可以将其映射到udf,则可以将udf拖到数据上下文中。当通过数据上下文访问时,LINQ-to-SQL可以进行翻译。

如果你只是过滤一个iqueryable,你可以编写一个方法,只使用Where(返回一个新的iqueryable),它可以很好地工作。

如果你需要更多的马克杯,你可能不得不手动弄乱表达树。

答案 3 :(得分:1)

你做了两件事:

  1. 在SQL中创建用户定义的标量函数:http://msdn.microsoft.com/en-us/library/bb386973.aspx
  2. 在Linq To SQL中调用它:http://msdn.microsoft.com/en-us/library/bb399416.aspx

答案 4 :(得分:1)

好的解决方案

声明一个类的属性,该类可以转换为远程LINQ执行 与Microsoft.Linq.Translations

  

examples

     

NuGet Package

     

Source on GitHub

答案 5 :(得分:0)

最简单的方法是弄清楚如何将'SatisfyFilter'函数转换为一系列具有可接受翻译的linq命令。我担心没有其他“简单”的方式来使用您的自定义功能,而不会将您的2500万客户端过滤到更具实现性的数字。