web-dev-qa-db-ja.com

Entity Framework / Linq EXpressionの文字列から整数への変換

私はそのような式を持っています:

_var values = Enumerable.Range(1,2);

return message => message.Properties.Any(
    p => p.Key == name 
    && int.Parse(p.Value) >= values[0] 
    && int.Parse(p.Value) <= values[1]);
_

これは正常にコンパイルされますが、データベースに到達すると例外をスローします'LINQ to Entities does not recognize the method 'Int32 Parse(System.String)' method, and this method cannot be translated into a store expression '

解析を行わず、値が_string[]_である場合、文字列に対して_>=_および_<=_演算子を使用できません。

_p.Value_はさまざまな値を保持する文字列ですが、この場合はintです。

このようなbetweenステートメントを実行するためにデータベースをクエリする方法はありますか?

17
Jon

コメントで他の人が指摘しているように、この値を解析する必要があるという事実は、データベースで別のデータ型を使用する必要があることを示す赤い旗であるべきです。

幸い、クエリをLINQ to EntitiesではなくLINQ to Objectsで強制的に実行することによる回避策があります。残念ながら、それは潜在的に大量のデータをメモリに読み込むことを意味します

[〜#〜]編集[〜#〜]

他のコメントに基づいて、[値]列の値が数値であるとは限りません。したがって、値を数値に変換してから、その変換の失敗/成功に基づいて処理する必要があります。

return message
       .Properties
       .AsEnumerable()
       .Any(p => 
            {
                var val = 0;
                if(int.TryParse(p.Value, out val))
                {
                    return p.Key == name &&
                           val >= values[0] &&
                           val <= values[1])
                }
                else
                {
                    return false;
                }
           );

編集2

実際には、データベースでこれを回避できる可能性があります。これがうまくいくかどうかはわかりませんが、試してみてください:

return message.Properties
              .Where(p => p.Key == name && SqlFunctions.IsNumeric(p.Value) > 0)
              .Any(p => Convert.ToInt32(p.Value) >= values[0] &&
                        Convert.ToInt32(p.Value) <= values[1]);
4
Justin Niessner

この答えは嫌いですが、実際の答えは簡単にはできません。本当の痛みでしょう。最初からデータベースフィールドを正しいタイプにしておくべきだと言っている多くの間違った答えや多くの答えを見てきましたが、これは役に立ちません。

あなたの質問は MSDNのこの質問 に似ています。

使用しているEFの種類に応じて、いくつかの可能性があります。

1. EDMXファイルを使用しています。

(最初にコーディングしたり、最初にリバースエンジニアリングしたコードではありません)。

あなたはこのようなものを使うことができます( この答えから ):

[EdmFunction("PlusDomain", "ParseDouble")]
public static double ParseDouble(string stringvalue)
{
    // This method exists for use in LINQ queries,
    // as a stub that will be converted to a SQL CAST statement.
    return System.Double.Parse(stringvalue);
}

次のようにEDMXにマッピングします。

<Function Name="ParseDouble" ReturnType="Edm.Double">
    <Parameter Name="stringvalue" Type="Edm.String" />
    <DefiningExpression>
        cast(stringvalue as Edm.Double)
    </DefiningExpression>
</Function>

2. EF> = 4.1で最初にコードを使用している場合。

お前、やっちゃったんだな。 Microsoftは、そのような関数をSqlFunctionsに追加するのに適しているとは考えていませんでした。期待できる最高の方法は、スカラーSQL関数をデータベースに追加し、(おそらく)コンテキストにマッピングしてみることです。マイクロソフトは、最初にこのようなことをコードで行うことに何の意味もないと考えました。幸いにも、彼らはそのようなものを完全にブロックしませんでした。 Fluent APIは強力です。

次のように関数またはストアドプロシージャを呼び出すことができます( 参照 ):

var outParam = new SqlParameter("overHours", SqlDbType.Int);
outParam.Direction = ParameterDirection.Output;

または、このように( 参照 ):

var data = context.Database.ExecuteSqlCommand("dbo.sp_getNumberJobs @overHours OUT", outParam);
int numJobs = (int)outParam.Value;

ただし、それらを実際にLINQ to Entitiesに統合するには、 EntityFramework.CodeFirstStoreFunctions NuGetパッケージを使用して、 CodeFirstFunctions のようなものが必要です。 SQL関数をコンテキストにマップしますが、.NET 4.5用にのみ作成された外部ライブラリを使用します( こちら を参照)。

代わりに、 この質問 のように手動で同じことを試みることができます。

私のニーズのために解決したより迅速な解決策は、変換された型でビューを作成することです。これにより、問題全体が回避されます。

15
Menace

最近、クエリを具体化せずに、LINQクエリで文字列(数値表現)を列挙値に変換する必要がありました。私の列挙は0と9の間のint値を使用したので、私は次のようなことをしました:

    .Select(str => (MyEnum?)(SqlFunctions.Unicode(str) - 48))

私はこれが問題の完全な解決策を提供していないことを知っていますが、間違いなく私のような状況で機能します。多分それは便利だと思うでしょう。

1
Adi