7

Ich benutze Entity Framework 6.x mit dem Code First Ansatz für eine MVC 5-Anwendung. In dieser besonderen Situation meines Modell (unter anderem) zwei Eigenschaften genannt Breite und Länge:Entity Framework Code Zuerst trunkiere ich meine Dezimalstellen

[Required, Range(-90, +90)] 
public decimal Latitude { get; set; } 

[Required, Range(-180, +180)] 
public decimal Longitude { get; set; } 

Und wenn ich die Migration durchgeführt habe ich so etwas wie diese

CreateTable("ResProperty"), c => new { 
     : 
    Latitude = c.Decimal(nullable: false, precision: 10, scale: 8), 
    Longitude = c.Decimal(nullable: false, precision: 11, scale: 8), 
     : 
}) 
... other stuff 

so sowohl geografische Breite und Länge haben 8 dezimal Ziffern. Ersteres mit 2 ganzen Zahlen (max. 90) und letzteres mit 3 ganzen Zahlen (max. 180).

Nach der Durchführung des Update-Befehl Datenbank sind meine Tabellenspalten wie folgt angezeigt:

Latitude decimal(10,8) 
Longitude decimal(11,8) 

, die mir gut scheint. Jetzt habe ich eine Karte und einen Javascript-Code, der es dem Benutzer ermöglicht, den Marker neu zu positionieren. Das funktioniert auch gut. Wenn der Marker neu positioniert wird, werden die Breiten- und Längengradfelder mit dem aktualisierten Wert gefüllt, der (Javascript) mehr als 12 Dezimalstellen hat. Das ist nicht wichtig, weil meine Skala 8 Dezimalstellen hat.

Nachdem der Submit-Button gedrückt wurde und entweder die POST-Methode Create oder Edit aufgerufen wurde, untersuche ich die Model-Instanz und bestätige, dass die im Controller übergebenen Werte korrekt sind, sie haben mehr als genug Dezimalstellen (diejenigen, die Javascript-Code platzieren). Also ist der Wert korrekt.

Nun ... das Problem ist, dass nachdem db.SaveChanges() ausgeführt wird, die Datenbank aktualisiert wird - und ich habe bestätigt, dass ein tatsächliches Schreiben/Update stattgefunden hat - aber irgendwie ignoriert die EF meine tatsächlichen Werte und schreibt abgeschnittene Breite/Länge gerundet auf NUR ZWEI Dezimalstellen, so dass mein Breitengrad im DB als 09.500000000 angezeigt wird, werden alle anderen Dezimalziffern auf Null gesetzt, weil eine Rundung stattgefunden zu haben scheint.

// Prior to SaveChanges() 
Latitude = 9.08521879 
Longitude = -79.51658792 
// After SaveChanges() 
Latitude = 9.08000000 
Longitude = -79.51000000 

Warum wird es gerundet, wenn ich die richtige Skalierung und Genauigkeit angegeben habe und die Spalte die richtige Skalierung und Genauigkeit hat? Warum ändert SaveChanges meine Werte?

Ich fand diesen Beitrag (http://weiding331.blogspot.com/2014/01/entity-framework-decimal-value.html) das ist das gleiche Problem, aber ich weiß nicht, wie ich das beheben kann (wenn es tut), weil ich bereits mehrere Migrationen und Datenhinzufügungen durchgeführt habe, nachdem die betreffende Tabelle "migriert wurde ".

Fasst

  • Der Modelldatentyp korrekt ist (dezimal)
  • Die Datenbankmigration Code hat die richtige precion/Skala (lat 08.10 lon 08.11)
  • die SQL-Datenbank Spalten haben die korrekte Präzision/Skala (lat 10/8, lang 11/8)
  • Die Werte, die im Modell übergeben werden, haben mindestens 8 Dezimalziffern für Breite und Länge
  • das tatsächliche Schreiben/die Aktualisierung des Wertes nimmt pla ce in der Datenbank ohne Fehler, aber ...
  • Die in der Datenbank erfassten Werte für diese beiden Spalten werden auf zwei Dezimalstellen abgeschnitten und zeigen auch die anderen am wenigsten signifikanten Dezimalstellen als Null (0)
+0

Haben Sie Größe und Präzision in Ihrem Modell angeben? Werfen Sie einen Blick auf diese Frage http://stackoverflow.com/questions/3504660/decimal-precision-and-scale-in-ef-code-first? Eine andere Anmerkung EF unterstützt räumliche Datentypen ... – Pawel

+0

Ich glaube nicht, dass ich OnModelCreating mehr verwenden konnte, da diese bestimmte Migration mehrere Ebenen in meiner Migrationsliste war. Ich fügte es post mortem hinzu und führte Update-Datenbank (ohne irgendeine neue Migration) aber sah es nicht, das Problem zu lösen. Außerdem zeigten die SQL-Spalten in der DB die korrekte Genauigkeit, aber EF schnitt sie während SaveChanges() intern ab. –

Antwort

6

EF eine spezielle Eigenschaft für SqlProviderServices hat (Umsetzung für den SqlClient-Anbieter für SQL Server) - TruncateDecimalsToScale. Der Standardwert ist wahr, vielleicht können Sie ihn in einen falschen Wert ändern. Zum Beispiel:

public class DbContextConfiguration : DbConfiguration 
    { 
     public DbContextConfiguration() 
     { 
      var now = SqlProviderServices.Instance; 
      SqlProviderServices.TruncateDecimalsToScale = false; 
      this.SetProviderServices(SqlProviderServices.ProviderInvariantName, SqlProviderServices.Instance); 
     } 
    } 

    [DbConfigurationType(typeof(DbContextConfiguration))] 
    public class MyContext : DbContext 
    { ... } 

Mehr Infos über das: https://msdn.microsoft.com/en-us/library/system.data.entity.sqlserver.sqlproviderservices.truncatedecimalstoscale%28v=vs.113%29.aspx

+0

Das sieht genau nach dem aus, was ich suche, aber könntest du erklären, wie der Wert hier eingestellt wird? Es gibt eine Variable "now", die anscheinend nicht verwendet wird und die Eigenschaft scheint auf eine statische Methode gesetzt zu sein. Ist dies der beste Weg diesen Wert zu setzen? Ich bin überrascht, dass ein so wichtiges Feature nicht mehr Dokumentation enthält - das Abschneiden von Dezimalzahlen ist sicherlich ein großes Problem. Vielen Dank. – Mark007

+0

@ Mark007 es ist eine globale Konfiguration. Natürlich ist es auch kein guter Ort, um diese Dinge einzurichten, aber Sie wissen, dass es EF ist;) –

+0

Es hat funktioniert und das Problem gelöst, aber ich denke, ich muss ILSpy Dinge und genau sehen, was passiert an einem bestimmten Punkt. – Mark007

Verwandte Themen