2016-04-28 14 views
2

私のコードは次のとおりです。C#とEntity Frameworkを使用して小さなフロート値をSQL Serverに挿入する

public class MyDbContext : DbContext 
{ 
    public virtual DbSet<CurrentData> CurrentData { get; set; } 
} 

public class CurrentData 
{ 
    public int ID { get; set; } 
    public DateTime Time { get; set; } 
    public float Value { get; set; } 
} 

... 

float f = 1.37E-40f; 

using (var context = new MyDbContext()) 
{ 
    var data = new CurrentData() { ID = 100, Time = DateTime.Now, Value = f }; 
    context.CurrentData.Add(data); 

    var result = context.SaveChanges(); 
} 

float値が小さいため、SaveChanges()で例外が発生します。

着信表形式データストリーム(TDS)リモートプロシージャコール(RPC)プロトコルストリームが正しくありません。パラメーター4(\ "@ 1 \"):指定された値は、データ型realの有効なインスタンスではありません。ソースデータに無効な値がないかチェックしてください。無効な値の例は、精度より大きいスケールを持つ数値型のデータです。

fを0に変更すると、正常に動作します。

SQL ServerのREALタイプ範囲を確認したとき、正の最小値は1.18E-38です。

https://msdn.microsoft.com/en-us/library/ms173773.aspx

C#でfloat値が1.18E-38よりも小さいのであれば、例外が発生します。

私はこの

if (f > 0 && f < 1.18E-38f) 
    f = 0; 
else if (f < 0 && f > -1.18E-38f) 
    f = 0; 

ようf値を変更しかし、私はそれが良い見ていないと思います。

もっと良い解決策はありますか?

私は、Entity FrameworkではなくSqlDataAdapterを使用してテストしましたが、同じ例外がありました。

は、私はあなたのデータベースがデータ型として

REAL

を持っているようですねEFのv6.1.3およびSQL Server 2012

+0

「数字」のみを格納し、mssqlの数値を計算する必要がない場合は、文字列リテラルとして格納することができますか? https://msdn.microsoft.com/en-us/library/sd9e25kz(v=vs.110).aspx – montewhizdoh

+0

@montewhizdohそうする必要はないからです。 SQL Server *は、スケールと精度がよく定義された '数値型 'を持っています(例:' numeric(19,5) ')。 –

+0

'' float'または 'real'を使ってはいけません。テーブルに必要な位取りと精度を持つ数値型を使用し、クラスに 'decimal'を使用します。一方、*なぜ*あなたはそのような小さな番号を使用したいですか? NULLをエミュレートしようとしていますか? –

答えて

2

ここでの問題は、x86アーキテクチャ上で動作しているときのC#がサポートする浮動小数点値を非正規化ということです。その結果、C#floatは、両方とも公称単精度浮動小数点型であっても、SQL Server REALよりも多くの値をサポートします。(さらに複雑な問題は、SQL ServerがFLOATと呼ぶものが実際には倍精度型であることです。これはC#がdoubleを呼び出すので、float != FLOATですが、これは問題ではありません)。

C#で非正規化された値を無効にする方法はありません。また、それらをテストする方法もありません。しかし、答えにはThis questionがあります。もちろん、SQL Server側の列の精度をFLOATに増やすこともできます。これはC#floatの範囲内のすべての値を非正規化さえ扱うことができます。もちろん、これはちょうどfloatに収まらないデータベースから値を読み取っているときに問題をシフトさせます。また、C#doubleを格納する必要がある場合には、SQLエンドに対応するより大きな型がないため、解決策はありません。

実際の用途では、単純に範囲チェックがうまくいくかもしれません。特にアプリケーションが実際に使用する範囲にそれを結び付けることができれば十分です。

+0

変換コードがユーザーコードであると思われますか?私はほとんどのユーザーがSQLの実数型としてc#floatを扱うかもしれないと思います。この場合、潜在的な問題があることを意味します。私はEFまたはSqlDataAdapterでこれを無視していくつかのオプションがあるはずだと思います。 –

+0

ユーザーは、C#のデータ型とSQL Serverのデータ型の違いをまず知らなくてはなりません。たとえば、C#の 'DateTime'は' 0001-01-01'の値をサポートしていますが、SQLの 'DATETIME'は値になりません。このような範囲の問題を単に無視することはできません。しかし、私はEFの著者ではなく、それに関する議論はSOの話題ではない。いつでもEFプロジェクトで問題を開くことができます。 –

0

と.NET 4.5.1を使用しました。それは

FLOAT

に切り替えるよりも

REAL

ある場合はそれを修正する必要があります。 REALは、保存しようとしている番号をサポートしていないことを以下の参照で確認できます。

参照:SQL Serverがないのに対し、

https://msdn.microsoft.com/en-us/library/ms173773.aspx

+1

倍精度は必要ないので、floatを選択しました。ありがとう。 –

+0

おかげさまで、私はあなたにフロートに切り替えることをお勧めします。その理由は、あなたのDBが "本物"であり、送信した番号のサイズをサポートしていないからです。 – montewhizdoh

関連する問題