3

私は使用linq2dbしていますが、ほとんどの CRUD 操作で十分に機能しますが、SQL に変換できない多くの式に遭遇しました。

どのような種類の式が関係するかを事前に正確に知っていて、以前にそれらを正常に呼び出していない限り、そこから得linq2dbられる利益よりも、見つけて削除しようとするコスト (またはサーバー側から離れてください)問題のある表現。

linq2dbその場しのぎで必要に応じて SQLに解析する方法を知っていればExpression<Func<T,out T>>、自信がつき、このツールを使用して多くのことができるようになります。

たとえば、 aと aを受け取り、区切り文字の間の各部分文字列のaを返すString.Split(char separator)メソッドを考えてみましょう。stringcharstring[]

私のテーブルに、コンマで区切られたさまざまな機器の使用法のリストを含むEquipmentnull 許容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

同時に、まさにそれを行う例(カスタム式を実装する人)を見ることができれば、これを処理する方法を完全に伝えることができるように感じます。

したがって、私の質問は次のとおりです。そのままでは解析できないan を解析する方法をどのよう指示すればよいですか?linq2dbExpression

4

2 に答える 2

4

数年前、私は次のようなことを書きました。

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]

PS。プロジェクトでlinq2dbを広く使用しており、完全に満足しています。しかし、はい、学習曲線があり (私たちが学ぶほとんどすべてのことと同様)、ライブラリに慣れて、それがもたらすすべての利点を確認するには、ライブラリを学習して遊んでみる必要があります。

于 2015-05-05T15:45:11.053 に答える
1

listOfListOfStringUsages.AsEnumerable() を試してください。クライアント側で SelectMany の実行を強制します。

アップデート:

問題を再現するために次のコードを使用しました。

var q =
    from t in db.Table
    where t.StringField != null
    select t.StringField.Split(' ');

var q1 = q
    //.AsEnumerable()
    .SelectMany(s => s)
    .Select(s => s.Trim())
    .Distinct()
    .ToList();

動いていない。しかし、.AsEnumerable() のコメントを外すと、問題なく動作します。

于 2015-05-03T23:05:14.037 に答える