EF Core: можно ли использовать `.HasConversion()` для преобразования SQL с плавающей запятой в десятичное число C#?

У меня есть различные существующие таблицы SQL, в которых есть столбцы float, в которых сохраняются цены, и мне нужно загрузить их в свойства C# decimal

Прочитав методы .HasConversion() и .HasColumnType(), я подумал, что смогу прочитать SQL-запятую (который EF Core должен знать, что это число с плавающей запятой из-за .HasColumnType(), а стажер переводит это в double), а затем преобразовать ее в десятичное число C#, используя метод .HasConversion(); затем наоборот для обратной записи.

Я неправильно понял или неправильно использую методы?


Контекст OnModelCreating

entity.Property(e => e.Price) // <-- decimal field
    .IsRequired()
    .HasColumnName("PREFIX-Price")
    .HasColumnType("float")
    .HasDefaultValueSql("((0))")
    .HasConversion(
        v => Decimal.ToDouble(v),
        v => Convert.ToDecimal(v)
    )

После запуска чего-то вроде:

var x = myContext.TableName.Select(x => x.Price);

Я получаю следующее исключение:

InvalidCastException: Unable to cast object of type 'System.Double' to type 'System.Decimal'.
System.Data.SqlClient.SqlBuffer.get_Decimal()
System.Data.SqlClient.SqlDataReader.GetDecimal(int i)
lambda_method(Closure , DbDataReader )
Microsoft.EntityFrameworkCore.Storage.Internal.TypedRelationalValueBufferFactory.Create(DbDataReader dataReader)

Я бы не ожидал, что он вызовет System.Data.SqlClient.SqlBuffer.get_Decimal(), а скорее получит float/double.

В конце концов, могу ли я делать то, что пытаюсь сделать?


Дополнительная информация:

(Хотя очевидно), если бы я вызвал нижеприведенное, то это работало бы нормально, но на самом деле это невозможно, так как я/другие могли бы забыть или не понять, плюс рабочая нагрузка!

var x = myContext.TableName.Select(x => Convert.ToDecimal(x.Price));

Миграция базы данных не вариант? Лично я бы перенес данные SQL в правильный тип данных, а затем построил бы свои модели, чтобы они соответствовали правильному состоянию. Невыполнение этого требования приведет к побочным эффектам.

Kieran Devlin 04.07.2019 17:30

К сожалению нет, 80-90% сайта размещено на классическом asp (настоящем олдскуле!). Я попробовал это на маленьком столе, который использовался всего на нескольких страницах, и у него были некоторые... побочные эффекты. Каждый экземпляр поля в старом классическом asp должен был быть заключен в CDBL(). Я пытаюсь заставить их перейти на NET CORE, но они хотят сохранить все внутренние функции, которые были специально добавлены на сайт.

glenn223 04.07.2019 17:42

Вы ознакомились с документацией по преобразованию значений в EF Core? docs.microsoft.com/en-us/ef/core/modeling/value-conversions

Kieran Devlin 04.07.2019 17:43

Обратите внимание, что хотя то, что вы пытаетесь сделать, возможно, при записи в базу данных будет потеря точности. (Я знаю, что это довольно очевидно, но я чувствую, что все равно должен это сказать)

Kieran Devlin 04.07.2019 17:45

Также обратите внимание, что нет встроенного преобразователя для числа с плавающей запятой в десятичное число, поэтому вам придется его определить.

Kieran Devlin 04.07.2019 17:47

@glenn223 какую версию EF Core вы используете? Кроме того, существуют ли другие свойства или сущности с десятичным типом CLR, которые сопоставляются с числом с плавающей запятой в базе данных? Почти уверен, что это сработает только с entity.Property(e => e.Price).HasColumnType("float");

Jan Paolo Go 04.07.2019 17:50

@KieranDevlin - Да, я прочитал документацию. Я надеюсь убедить их мигрировать, а затем, когда сайт использует только NET Core, переключите столбцы SQL. Последний комментарий, я думал, что это то, что я делал с методом HasConversion

glenn223 04.07.2019 17:53

@JanPaoloGo - я бегу "Microsoft.EntityFrameworkCore": "2.2.0". В проекте .NET Core нет рабочих свойств. Тем не менее, он отлично работает в старом .NET Framework проекте (другая зависимость), который был запущен ненадолго до перехода на Core.

glenn223 04.07.2019 18:10

«Поплавок» SQL Server удвоен, чтобы все было ясно. Двойное число нельзя преобразовать в десятичное, потому что его диапазон значений намного больше; double.MaxValue есть 1,79769313486232E+308, decimal.MaxValue "только" 79228162514264337593543950335.

Gert Arnold 04.07.2019 21:39
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
9
2 866
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вам нужно будет создать свой собственный конвертер значений следующим образом:

var converter = new ValueConverter<decimal, double>(
    v => (double)v,
    v => (decimal)v
);

а затем используйте его в конфигурации свободного API:

modelBuilder
    .Entity<EntityType>()
    .Property(e => e.FeildName)
    .HasConversion(converter);

Точно попробовал ваш код. Извините, не сработало. Хотя это может быть конверсия float to decimal и я делаю double to decimal, но не повезло

glenn223 04.07.2019 18:04

Извините за ошибку, попробуйте с двойным. Я только что создал консольное приложение, чтобы воспроизвести это, и мне удалось его преобразовать, поэтому, если вы хотите, чтобы я отправил вам репо, я могу. Я обновил ответ, чтобы отразить правильный тип.

Kieran Devlin 04.07.2019 18:22

Я просто попытался изменить его на десятичное число, а также переместить его из встроенной модели объекта (например, моей) в цепной вызов (например, ваш), и все равно не повезло. Если бы вы могли отправить репо, пожалуйста. Один быстрый вопрос: ваше e.FieldName десятичное свойство? Просто хочу убедиться, что моя собственность public decimal Price { get; set; }

glenn223 04.07.2019 18:39

Да, FeildName имеет тип decimal, а схема SQL, на которую он сопоставляется, имеет тип float.

Kieran Devlin 04.07.2019 19:17

Извините, что так долго, демо было на моем рабочем ноутбуке. gitlab.com/KieranDevvs/efvalueconversiontest Надеюсь, это поможет.

Kieran Devlin 05.07.2019 10:09

Давайте продолжить обсуждение в чате.

Kieran Devlin 05.07.2019 10:14

Другие вопросы по теме