مفهوم تعریف نوع decimal پیشفرض در SQL Server
فرض کنید از EF پیش از EF Core استفاده میکنید که به صورت پیشفرض، نوع System.Decimal را در مدلهای شما به همان decimal در SQL Server نگاشت میکند. فکر میکنید در این حالت خروجی کوئریهای زیر چه چیزی خواهد بود؟
select '0.4400' as Expected , cast(0.4400 as decimal) as Actual select '1.3200' as Expected, cast(1.3200 as decimal) as Actual select '1.7600' as Expected, cast(1.7600 as decimal) as Actual select '65.0000' as Expected, cast(65.0000 as decimal) as Actual select '99.50' as Expected, cast(99.50 as decimal) as Actual
این خروجی را در تصویر ذیل مشاهده میکنید. در اینجا خصوصا به مورد صفر دقت کنید:
علت اینجا است که از دیدگاه SQL Server، نوع decimal پیشفرض، دقیقا به معنای decimal(18,0) است که به آرگومان اول آن، precision و به آرگومان دوم آن، scale میگویند. یعنی حداکثر چه تعداد رقم دسیمال، پیش از ممیز و چه تعداد عدد دسیمال، پس از ممیز قرار است در این نوع داده ذخیره شوند.
بنابراین باتوجه به اینکه در حالت پیشفرض، مقدار scale و یا همان تعداد ارقام مجاز پس از ممیز، صفر است، عدد ارائه شده، به نزدیکترین عدد صحیح ممکن، گرد خواهد شد.
به همین جهت برای رفع این مشکل، باید دقیقا مشخص کرد که scale نوع دادهای decimal مدنظر چیست. برای مثال میتوان از decimal(10,4) استفاده کرد که در اینجا، نتایج صحیحی را ارائه میدهد:
همچنین به عنوان تمرین، مثال زیر را حل کنید!
select iif(cast(0.1 + 0.2 as decimal) = 0, 'true', 'false')
بنابراین باید بهخاطر داشت، اگر از EF 6x (پیش از EF Core) استفاده میشود، حتما نیاز است مقادیر precision و scale را دقیقا مشخص کنیم؛ وگرنه حالت پیشفرض آن decimal(18,0) است:
modelBuilder.Properties<decimal>().Configure(x => x.HasPrecision(18, 6));
رفتار EF Core با نوع دادهای decimal
رفتار EF Core با نوع دادهای decimal بهبود یافته و حالت پیشفرض آن، بدون هیچگونه تنظیمی، نگاشت به decimal(18,2) است. به علاوه اگر این پیشفرض را هم تغییر ندهیم، در حین اعمال Migration، پیام اخطاری را نمایش میدهد:
No store type was specified for the decimal property 'Price' on entity type 'Product'. This will cause values to be silently truncated if they do not fit in the default precision and scale. Explicitly specify the SQL server column type that can accommodate all the values in 'OnModelCreating' using 'HasColumnType', specify precision and scale using 'HasPrecision', or configure a value converter using 'HasConversion'.
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) { configurationBuilder.Properties<decimal>().HavePrecision(18, 6); }
دو مطلب مرتبط
- از نوعهای دادهای float و یا double در مدلهای EF خود استفاده نکنید.
- همیشه مراقب بزرگ شدن اعداد و مبالغ و جمع نهایی آنها باشید!