7

Я использую Entity Framework 6.x, используя подход Code First в приложении MVC 5. В этой конкретной ситуации моя модель (среди прочего) содержит два свойства с именами Широта и долгота:Entity Framework Code Сначала усечение десятичных знаков

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

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

И когда я выполнил миграцию я получил что-то вроде этого

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

так как широта и долгота имеют 8 decimal цифры. Первый имеет 2 целых числа (макс. 90), а второй - 3 целых числа (макс. 180).

После выполнения Update-Database команду столбцы моей таблице показаны как:

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

, что кажется хорошо для меня. Теперь, на мой взгляд, у меня есть код карты и Javascript, который позволяет пользователю переместить маркер. Это хорошо работает. Когда маркер перемещается, поля Latitude и Longitude заполняются обновленным значением, которое (Javascript) имеет более 12 десятичных цифр. Это не имеет значения для AFAIK, потому что мой масштаб равен 8 десятичным знакам.

После нажатия кнопки отправки и запускается метод Create или Edit POST. Я рассматриваю экземпляр модели, и я подтвердил, что фактические значения, переданные в модели контроллеру, верны, они имеют более чем десятичные цифры (те, что Javascript код места). Поэтому значение правильное.

Теперь проблема заключается в том, что после выполнения db.SaveChanges() база данных обновляется, и я подтвердил, что фактическая запись/обновление произошла, но как-то внутри EF игнорирует мои фактические значения и пишет усеченная широта/долгота округлена до ТОЛЬКО ДВА десятичных цифр, поэтому моя Локатор показывает в БД как 09.500000000 все остальные десятичные цифры обнуляются, потому что округление, похоже, имело место.

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

Почему это округление, если я дал правильный масштаб и точность, а столбец имеет правильный масштаб и точность, а? почему SaveChanges меняет мои значения?

Я нашел это сообщение (http://weiding331.blogspot.com/2014/01/entity-framework-decimal-value.html), что является той же проблемой, но я не знаю, как я могу это исправить (если это так), потому что я уже выполнил несколько миграций и добавлений данных после того, как таблица была «перенесена» ».

Резюмируя

  • Тип модели данных является правильным (десятичное)
  • код миграции базы данных имеет правильный precion/масштаб (лат 10/8 11/8) LON
  • столбцы базы данных SQL (лат 10/8, длинный 11/8)
  • Значения, переданные в модели, имеют как минимум 8 десятичных цифр для широты и долготы
  • фактическое написание/обновление значения принимает pla ce в базе данных без ошибок, но ...
  • значения, записанные в базе данных для этих двух столбцов обрезаются до двух знаков после запятой и показать другие значащих десятичных цифр, как ноль (0)
+0

ли вы указать масштаб и точность в вашей модели? Взгляните на этот вопрос: http://stackoverflow.com/questions/3504660/decimal-precision-and-scale-in-ef-code-first? В другом примечании EF поддерживает пространственные типы данных ... – Pawel

+0

Я не думаю, что я мог бы использовать OnModelCreating больше, потому что эта конкретная миграция была несколько уровней в моем списке перенаправления. Я добавил его post mortem и запустил Update-Database (без какой-либо новой миграции), но не видел, чтобы он решил проблему. Кроме того, столбцы SQL в БД действительно отображали правильную точность, но EF обрезал ее внутренне во время SaveChanges(). –

ответ

6

EF имеет специальное свойство для SqlProviderServices (реализация для поставщика SqlClient для SQL Server) - TruncateDecimalsToScale. Значение по умолчанию равно true, поэтому, возможно, вы можете изменить его на значение false. Например:

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 
    { ... } 

Более подробную информацию о том, что: https://msdn.microsoft.com/en-us/library/system.data.entity.sqlserver.sqlproviderservices.truncatedecimalstoscale%28v=vs.113%29.aspx

+0

Это похоже на то, что я ищу, но не могли бы вы объяснить, как здесь задается значение? Существует переменная «now», которая, похоже, не используется, и свойство, похоже, установлено на статический метод. Это лучший способ установить это значение? Я удивлен, что такая важная функция не имеет больше документации вокруг нее - усечение десятичных знаков, несомненно, является серьезной проблемой. Благодарю. – Mark007

+0

@ Mark007 - глобальная конфигурация. Конечно, это нехорошее место для настройки этих вещей, но вы знаете, что это EF;) –

+0

Это сработало и решило проблему, но я думаю, что мне нужно, чтобы вещи ILSpy и точно видели, что происходит в какой-то момент. – Mark007

Смежные вопросы