2016-09-13 2 views
1

Alles, ich schreibe eine Anwendung, die eine Verbindung zu einem Oracle Server über die .NET Entity Framework in C#. Ich kann Daten einfach einfügen. Außerdem kann ich die meisten Daten problemlos abfragen. Die Ausnahme, die ich sehe, kommt von NUMBER oder FLOAT in Oracle, die zu .NET Typ decimal umgewandelt werden. Aber es passiert nicht immer.Oracle Entity Framework 'Angegebener Cast ist nicht gültig' GetDecimal

Wenn ich diese Nummer in Oracle "0.96511627906976744186046511627906976744" habe, dann bekomme ich die Ausnahme. Nicht während der LINQ Abfrage, aber wenn ich einen foreach mit den abgefragten Daten ausführen. Aber, wenn ich 0,9651162790 in der Zelle habe, funktioniert die Abfrage gut.

Soll Oracle Entity Framework die Genauigkeit nicht auf die eines decimal Typs reduzieren?

Abisolierpräzision der Hunderte von Millionen Einträge in unserer Datenbank ist offensichtlich keine Option. Hier

ist ein Code:

using (Entities context = new Entities()) 
{ 
    var data = from row in context.YieldsTestWeeklies 
       select new 
       { 
        D2Yield = row.D2Yield 
       }; 

    foreach (var row in data) 
    { 
     textBox1.AppendText(row.D2Yield.ToString() + Environment.NewLine); 
    } 
} 

Das Modell:

public partial class YieldsTestWeekly 
{ 
    public Nullable<decimal> D2Yield { get; set; } 
} 

Ausnahmedetails:

Nachricht: Die angegebene Umwandlung ist ungültig. Quelle: Oracle.ManagedDataAccess Innerexception: null Target: {System.Decimal GetDecimal (Int32)}

Stacktrace:

bei Oracle.ManagedDataAccess.Client.OracleDataReader.GetDecimal (Int32 i) bei Oracle. ManagedDataAccess.Client.OracleDataReader.GetValue (Int32 i) bei System.Data.Entity.Core.Common.Internal.Materialization.Shaper.ErrorHandlingValueReader 1.GetUntypedValueDefault (DbDataReader Leser, Int32 Ordinal) bei System.Data.Entity.Core. Common.Internal.Materialization.Shaper.ErrorHandlingValueReader 1.GetValue (DbDataReader-Leser, Int32-Ordinalzahl) bei Lambda_method (Closure, Former) bei System.Data.Entity.Core.Common.Internal.Materialization.Coordinator 1.ReadNextElement (Shaper Shaper) bei System.Data.Entity.Core.Common.Internal.Materialization.Shaper 1 .SimpleEnumerator.MoveNext() bei System.Data.Entity.Internal.LazyEnumerator`1.MoveNext() bei Oracle_Example.Form1.button1_Click (Objekt Absender, EventArgs e) in C: \ Benutzer \ REMOVED \ Desktop \ Oracle Beispiel \ Oracle Beispiel \ Form1.cs: Zeile 33 bei System.Windows.Forms.Control.OnClick (EventArgs e) bei System.Windows.Forms.Button.OnClick (EventArgs e) bei System.Windows.Forms.Button.OnMouseUp (MouseEventArgs mevent) bei System.Windows.Forms.Control.WmMouseUp (Nachricht & m, Schaltfläche MouseButtons, Int32 Klicks) bei System.Windows.Forms.Control.WndProc (Message & m) bei System.Windows.Forms.ButtonBase.WndProc (Message & m) bei System.Windows.Forms.Button.WndProc (Message & m) an System.Windows.Forms.Control.ControlNativeWindow.OnMessage (Nachricht & m) bei System.Windows.Forms.Control.ControlNativeWindow.WndProc (Message & m) bei System.Windows.Forms.NativeWindow.DebuggableCallback (IntPtr hWnd, Int32 msg, IntPtr WParam, IntPtr lparam) bei System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW (MSG & msg) bei System. Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop (IntPtr dwComponentID, Int32-Ursache, Int32 pvLoopData) bei System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner (Int32-Ursache, ApplicationContext-Kontext) bei System.Windows.Forms.Application.ThreadContext.RunMessageLoop (Int32 Grund, ApplicationContext-Kontext) bei System.Windows.Forms.Application.Run (Formular mainForm) bei Oracle_Example.Program.Main() in C: \ Users \ REMOVE D \ Desktop \ Oracle Beispiel \ Oracle Beispiel \ Programm.cs: Zeile 19 bei System.AppDomain._nExecuteAssembly (RuntimeAssembly-Assembly, String [] args) bei System.AppDomain.ExecuteAssembly (String AssemblyFile, Evidence AssemblySecurity, String [] args) bei Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() bei System.Threading.ThreadHelper.ThreadStart_Context (Object state) bei System.Threading.ExecutionContext.RunInternal (ExecutionContext ExecutionContext, Contextcallback, Objektzustand, Boolean preserveSyncCtx) System.Threading.ExecutionContext.Run (ExecutionContext executionContext, ContextCallback-Rückruf, Objektstatus, Boolean preserveSyncCtx) bei System.Threading.ExecutionContext.Run (ExecutionContext executionContext, ContextCallback-Rückruf, Object stat e) bei System.Threading.ThreadHelper.ThreadStart()

aktualisieren

habe ich versucht, diese beiden. Keine Arbeit. Und ich habe sie auch mit wirklich niedrigen Nummern ausprobiert.

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Conventions.Remove<DecimalPropertyConvention>(); 
    modelBuilder.Conventions.Add(new DecimalPropertyConvention(38, 18)); 
    base.OnModelCreating(modelBuilder); 
} 

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Entity<YieldsTestWeekly>().Property(e => e.D2Yield).HasPrecision(38, 18); 
    base.OnModelCreating(modelBuilder); 
} 

Update (neue Frage) Weiß jemand, ob es möglich ist, diese Objekte abzufangen und sie gestutzt, bevor sie in das Modell platziert werden? Ich habe das Gefühl, dass ich in der Lage sein sollte, etwas zu übergehen, um dies zu ermöglichen, aber ich weiß nicht einmal, wo ich anfangen soll.

+1

Sie sind nicht der einzige - https://community.oracle.com/thread/3951568?start=0&tstart=0 –

Antwort

1

Sie erhalten den gleichen Fehler mit ADO. Net, da das Problem in der ADO. Net-Provider (EF, während "Materialisierungsprozess" finden Sie, dass die Zieleigenschaft ist ein Dezimal so GetDecimal des Oracle Data Reader aufgerufen wird) .

Um zu verstehen, während es nur manchmal passiert, können Sie sich die GetDecimal-Implementierung ansehen. Wahrscheinlich konvertiert Oracle implizit nur dann eine Zahl, wenn die Konvertierung ohne Genauigkeitsverlust erfolgen kann; Andernfalls wird die Nummer nicht konvertiert und der Fehler ausgelöst. Andere Anbieter konvertieren einfach nicht kompatible Typen (so erhalten Sie den Fehler nicht immer nur bei bestimmten Datensätzen).

Die beste Lösung ist wahrscheinlich, das Feld zu verdoppeln und zu verwenden.
Sie können das doppelte Feld auch in eine Dezimalzahl konvertieren (wenn Sie möchten, können Sie dies in derselben Klasse mit einem nicht zugeordneten Feld tun). Mit dieser Lösung können Sie das konvertierte Feld nicht in Abfragen verwenden.

EDIT

las ich den ADO.Net Provider-Code und ist ziemlich seltsam.
Zuerst ruft EF GetValue auf und ist der Oracle ADO-Provider, der GetDecimal aufruft.Im Oracle-Provider ruft Get_everythingwithapoint eine innere GetDecimal-Funktion auf. Und ich denke, dass das Problem da ist, also wird meine Lösung nicht funktionieren. Ich denke, dass der einzige Weg ist, dass Oracle den ADO.Net-Provider behebt.

Nur für den Fall fügen ich hier einige Code

von Datareader

override public decimal GetDecimal(int i) { 
    AssertReaderIsOpen(); 
    AssertReaderHasData(); 
    return _columnInfo[i].GetDecimal(_buffer); 
} 

von OracleColumn (die Art der _columnInfo)

internal decimal GetDecimal(NativeBuffer_RowBuffer buffer) { 
     if (typeof(decimal) != _metaType.BaseType) { 
      throw ADP.InvalidCast(); 
     } 
     if (IsDBNull(buffer)) { 
      throw ADP.DataReaderNoData(); 
     } 
     Debug.Assert(null == _longBuffer, "dangling long buffer?"); 

     decimal result = OracleNumber.MarshalToDecimal(buffer, _valueOffset, _connection); 
     return result; 
    } 

    internal double GetDouble(NativeBuffer_RowBuffer buffer) { 
     if (typeof(decimal) != _metaType.BaseType) { 
      throw ADP.InvalidCast(); 
     } 
     if (IsDBNull(buffer)) { 
      throw ADP.DataReaderNoData(); 
     } 
     Debug.Assert(null == _longBuffer, "dangling long buffer?"); 

     decimal decimalValue = OracleNumber.MarshalToDecimal(buffer, _valueOffset, _connection); 
     double result = (double)decimalValue; 
     return result; 
    } 

Sehen Sie, dass GetDouble die gleiche wie GetDecimal ist

Sie können auch OracleNumber.MarshalToDecimal bu schauen t Ich denke, dass Sie zu dem Schluss kommen werden, dass Sie es auch dann nicht sehen werden, wenn Sie ADO.Net verwenden.

+0

Wenn es keine Möglichkeit gibt, eine Oracle-Nummer oder Float in eine C# -Ziffer zu konvertieren, was war das Punkt von ihnen sogar Entity Framework-Funktionalität hinzufügen? Wenn ich es auf ein Double abbilde, verliere ich noch mehr Präzision. Und ich sehe nicht, wie es für ein Doppel noch nicht fehlschlagen würde. – ozziwald

+0

Bearbeitete die Antwort. Wahrscheinlich ist ein Oracle Bug und es gibt keine Lösung. Auch mit ADO.Net-Provider ohne EF – bubi

+0

könnte verwandt sein https://chrismay.org/2015/07/30/bug-in-oracledatareader-causing-invalidcastexception/ –

Verwandte Themen