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

Tan*_*ira 8 .net c# linq .net-4.0 linq-to-sql

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

return manager.Clients.SelectAll().Where(cli => cli.Name.SatisfyFilter(filter.Name) && cli.LastName.SatisfyFilter(filter.LastName) && cli.MiddleName.SatisfyFilter(filter.MiddleName)).ToList();
Run Code Online (Sandbox Code Playgroud)

但我明白了:

"方法'布尔SatisfyFilter(System.String,System.String)'没有支持的SQL转换."

错误

我的方法是:

public static bool SatisfyFilter(this string palavra, string filtro)
Run Code Online (Sandbox Code Playgroud)

同样的事情

public bool Contains(string value)
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

Jon*_*nna 8

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

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

public bool SatisfiesFilter(string name, string filter)
{
  // some sort of implementation.
}
Run Code Online (Sandbox Code Playgroud)

使用[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)
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

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


Tom*_*cek 4

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

  • 如果您需要类似的东西,则需要显式创建表达式树(用作 lambda 表达式的主体)。一种直接的方法是使用类的方法Expression,但它可以简化很多。

  • 也许最好的选择是使用LINQKit 项目。它使得调用其他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;
    
    Run Code Online (Sandbox Code Playgroud)

    customFunction是一个编译为表达式树的 lambda 函数,您可以在查询中使用它。该AsExpandable扩展将 use 替换为函数体,因此 LINQ to SQL 转换器可以处理此问题。您可以在我的博客文章中详细了解其工作原理。

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