У меня есть различные существующие таблицы 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));
К сожалению нет, 80-90% сайта размещено на классическом asp (настоящем олдскуле!). Я попробовал это на маленьком столе, который использовался всего на нескольких страницах, и у него были некоторые... побочные эффекты. Каждый экземпляр поля в старом классическом asp должен был быть заключен в CDBL(). Я пытаюсь заставить их перейти на NET CORE, но они хотят сохранить все внутренние функции, которые были специально добавлены на сайт.
Вы ознакомились с документацией по преобразованию значений в EF Core? docs.microsoft.com/en-us/ef/core/modeling/value-conversions
Обратите внимание, что хотя то, что вы пытаетесь сделать, возможно, при записи в базу данных будет потеря точности. (Я знаю, что это довольно очевидно, но я чувствую, что все равно должен это сказать)
Также обратите внимание, что нет встроенного преобразователя для числа с плавающей запятой в десятичное число, поэтому вам придется его определить.
@glenn223 какую версию EF Core вы используете? Кроме того, существуют ли другие свойства или сущности с десятичным типом CLR, которые сопоставляются с числом с плавающей запятой в базе данных? Почти уверен, что это сработает только с entity.Property(e => e.Price).HasColumnType("float");
@KieranDevlin - Да, я прочитал документацию. Я надеюсь убедить их мигрировать, а затем, когда сайт использует только NET Core, переключите столбцы SQL. Последний комментарий, я думал, что это то, что я делал с методом HasConversion
@JanPaoloGo - я бегу "Microsoft.EntityFrameworkCore": "2.2.0". В проекте .NET Core нет рабочих свойств. Тем не менее, он отлично работает в старом .NET Framework проекте (другая зависимость), который был запущен ненадолго до перехода на Core.
«Поплавок» SQL Server удвоен, чтобы все было ясно. Двойное число нельзя преобразовать в десятичное, потому что его диапазон значений намного больше; double.MaxValue есть 1,79769313486232E+308, decimal.MaxValue "только" 79228162514264337593543950335.





Вам нужно будет создать свой собственный конвертер значений следующим образом:
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, но не повезло
Извините за ошибку, попробуйте с двойным. Я только что создал консольное приложение, чтобы воспроизвести это, и мне удалось его преобразовать, поэтому, если вы хотите, чтобы я отправил вам репо, я могу. Я обновил ответ, чтобы отразить правильный тип.
Я просто попытался изменить его на десятичное число, а также переместить его из встроенной модели объекта (например, моей) в цепной вызов (например, ваш), и все равно не повезло. Если бы вы могли отправить репо, пожалуйста. Один быстрый вопрос: ваше e.FieldName десятичное свойство? Просто хочу убедиться, что моя собственность public decimal Price { get; set; }
Да, FeildName имеет тип decimal, а схема SQL, на которую он сопоставляется, имеет тип float.
Извините, что так долго, демо было на моем рабочем ноутбуке. gitlab.com/KieranDevvs/efvalueconversiontest Надеюсь, это поможет.
Давайте продолжить обсуждение в чате.
Миграция базы данных не вариант? Лично я бы перенес данные SQL в правильный тип данных, а затем построил бы свои модели, чтобы они соответствовали правильному состоянию. Невыполнение этого требования приведет к побочным эффектам.