c# - 当 linq2db 不知道如何转换给定的表达式,即 Split(char) 到 SQL 时,我如何告诉它如何转换?

标签 c# linq linq-to-sql extension-methods linq2db

我正在使用 linq2db 虽然它对于大多数 CRUD 操作来说工作得很好,但我遇到过许多它无法转换为 SQL 的表达式。

它已经到了这样的地步,除非我事先确切知道将涉及哪些类型的表达式并且之前已经成功调用它们,否则我担心从 linq2db 中获得任何好处。尝试查找然后删除(或从服务器端移走)违规表达式的成本将超过成本。

如果我知道怎么说 linq2db如何解析 Expression<Func<T,out T>>或任何时候在临时的、按需的基础上导入 SQL 之类的东西,这样我就会更有信心,并且我可以使用这个工具做很多事情。

例如,String.Split(char separator) ,采用 string 的方法和一个 char返回 string[]分隔符之间的每个子字符串。

假设我的表 Equipment有一个可为空的 varchar领域 Usages其中包含以逗号分隔的不同设备用途列表。

我需要实现 IList<string> GetUsages(string tenantCode, string needle = null)这将为给定租户代码和可选搜索字符串提供用法列表。

我的查询将类似于:

var listOfListOfStringUsages =
    from et in MyConnection.GetTable<EquipmentTenant>()
    join e in MyConnection.GetTable<Equipment>() on et.EquipmentId = e.EquipmentId
    where (et.TenantCode == tenantCode)
    where (e.Usages != null)
    select e.Usages.Split(','); // cannot convert to sql here

var flattenedListOfStringUsages = 
    listOfListOfStringUsages.SelectMany(strsToAdd => strsToAdd)
                            .Select(str => str.Trim())
                            .Distinct();

var list = flattenedListOfStringUsages.ToList();

但是,它实际上会在运行时在注释指示的行上爆炸。

我完全明白 linq2db的创作者不可能期望提供所有 string 的组合方法和主要数据库包。

与此同时,如果我能看到一个这样做的例子(有人实现自定义表达式),我觉得好像可以完全告诉它如何处理这个问题。

所以我的问题是:如何指示linq2db关于如何解析 Expression它不能开箱即用地解析?

最佳答案

几年前我写过这样的东西:

public class StoredFunctionAccessorAttribute : LinqToDB.Sql.FunctionAttribute
{
    public StoredFunctionAccessorAttribute()
    {
        base.ServerSideOnly = true;
    }

    // don't call these properties, they are made private because user of the attribute must not change them
    // call base.* if you ever need to access them
    private new bool ServerSideOnly { get; set; }
    private new int[] ArgIndices { get; set; }
    private new string Name { get; set; }
    private new bool PreferServerSide { get; set; }

    public override ISqlExpression GetExpression(System.Reflection.MemberInfo member, params ISqlExpression[] args)
    {
        if (args == null)
            throw new ArgumentNullException("args");

        if (args.Length == 0)
        {
            throw new ArgumentException(
                "The args array must have at least one member (that is a stored function name).");
        }

        if (!(args[0] is SqlValue))
            throw new ArgumentException("First element of the 'args' argument must be of SqlValue type.");

        return new SqlFunction(
            member.GetMemberType(),
            ((SqlValue)args[0]).Value.ToString(),
            args.Skip(1).ToArray());
    }
}

public static class Sql
{
    private const string _serverSideOnlyErrorMsg = "The 'StoredFunction' is server side only function.";

    [StoredFunctionAccessor]
    public static TResult StoredFunction<TResult>(string functionName)
    {
        throw new InvalidOperationException(_serverSideOnlyErrorMsg);
    }

    [StoredFunctionAccessor]
    public static TResult StoredFunction<TParameter, TResult>(string functionName, TParameter parameter)
    {
        throw new InvalidOperationException(_serverSideOnlyErrorMsg);
    }
}

...

[Test]
public void Test()
{
    using (var db = new TestDb())
    {
        var q = db.Customers.Select(c => Sql.StoredFunction<string, int>("Len", c.Name));
        var l = q.ToList();
    }
}

(当然,您可以围绕 Sql.StoredFunction() 方法编写包装器,以避免每次都将函数名称指定为字符串)

生成的sql(用于上面代码中的测试):

SELECT
    Len([t1].[Name]) as [c1]
FROM
    [dbo].[Customer] [t1]

附言。我们在我们的项目中广泛使用了 linq2db,并且对它非常满意。但是,是的,有一个学习曲线(就像我们学习的几乎所有严肃的东西一样),人们需要花一些时间学习和使用库,以便对它感到舒服并看到它可以提供的所有好处。

关于c# - 当 linq2db 不知道如何转换给定的表达式,即 Split(char) 到 SQL 时,我如何告诉它如何转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30014921/

相关文章:

c# - 从事件中删除空处理程序有任何副作用吗?

c# - 显示 C# winforms 编辑控件的提示

.net - Linq 表达式 : The binary operator Equal is not defined for the types 'MyEnum' and 'System.Enum'

asp.net-mvc - 用于检查 linq to sql 数据上下文中的唯一性的通用验证属性

c# - Linq to SQL 从不返回正确结果的查询中返回多个计数

sql - Linq to SQL intellisense 不知道数据上下文对象中的表

c# - HttpWebRequest UserAgent setter - 此属性未由此类实现

c# - Azure Key Vault .NET - 找不到方法

c# - 将大量整数加入 LINQ 查询

c# Dapper - 在 QueryAsync 方法上使用 linq