Bu kod ilk yaklaşım ile deniyorum, ama şimdi System.Decimal türü bir özellik türü ondalık (18, 0) bir sql sütun eşlenir olduğunu öğrendim.
Veritabanı sütununun hassasiyetini nasıl ayarlarım?
Bu kod ilk yaklaşım ile deniyorum, ama şimdi System.Decimal türü bir özellik türü ondalık (18, 0) bir sql sütun eşlenir olduğunu öğrendim.
Veritabanı sütununun hassasiyetini nasıl ayarlarım?
Yanıtlar:
Dave Van den Eynde'nin yanıtı artık güncel değil. EF 4.1'den itibaren ModelBuilder sınıfı artık DbModelBuilder ve imzası olan bir DecimalPropertyConfiguration.HasPrecision Yöntemi var: 2 önemli değişiklik var:
public DecimalPropertyConfiguration HasPrecision(
byte precision,
byte scale )
Burada kesinlik, ondalık noktanın nereye düştüğüne ve ölçeğin saklayacağı ondalık basamak sayısına bakılmaksızın, db'nin depolayacağı toplam basamak sayısıdır.
Bu nedenle, gösterildiği gibi özellikleri yinelemeye gerek yoktur, ancak
public class EFDbContext : DbContext
{
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Class>().Property(object => object.property).HasPrecision(12, 10);
base.OnModelCreating(modelBuilder);
}
}
System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder
base.OnModelCreating(modelBuilder);
. Bu kasıtlı mı yoksa sadece IDE yerine çevrimiçi kod yazmanın kurbanı mıydı?
decimals
EF6'daki herkes için hassasiyeti ayarlamak isterseniz, aşağıdakilerde DecimalPropertyConvention
kullanılan varsayılan sözleşmeyi değiştirebilirsiniz DbModelBuilder
:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<DecimalPropertyConvention>();
modelBuilder.Conventions.Add(new DecimalPropertyConvention(38, 18));
}
DecimalPropertyConvention
EF6'daki varsayılan decimal
özellikler özellikleridecimal(18,2)
sütunlarla .
Tek tek özelliklerin belirli bir kesinliğe sahip olmasını istiyorsanız, kuruluşun özelliğine ilişkin hassasiyeti aşağıdakiler üzerinde ayarlayabilirsiniz DbModelBuilder
:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<MyEntity>().Property(e => e.Value).HasPrecision(38, 18);
}
Veya, EntityTypeConfiguration<>
kesinlik düzeyini belirten varlık için bir ekleyin :
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new MyEntityConfiguration());
}
internal class MyEntityConfiguration : EntityTypeConfiguration<MyEntity>
{
internal MyEntityConfiguration()
{
this.Property(e => e.Value).HasPrecision(38, 18);
}
}
Bunun için bir Özel Özellik oluşturmak için güzel bir zaman geçirdim:
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
public sealed class DecimalPrecisionAttribute : Attribute
{
public DecimalPrecisionAttribute(byte precision, byte scale)
{
Precision = precision;
Scale = scale;
}
public byte Precision { get; set; }
public byte Scale { get; set; }
}
böyle kullanmak
[DecimalPrecision(20,10)]
public Nullable<decimal> DeliveryPrice { get; set; }
ve sihir, model oluşturmada biraz yansımayla olur
protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
{
foreach (Type classType in from t in Assembly.GetAssembly(typeof(DecimalPrecisionAttribute)).GetTypes()
where t.IsClass && t.Namespace == "YOURMODELNAMESPACE"
select t)
{
foreach (var propAttr in classType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.GetCustomAttribute<DecimalPrecisionAttribute>() != null).Select(
p => new { prop = p, attr = p.GetCustomAttribute<DecimalPrecisionAttribute>(true) }))
{
var entityConfig = modelBuilder.GetType().GetMethod("Entity").MakeGenericMethod(classType).Invoke(modelBuilder, null);
ParameterExpression param = ParameterExpression.Parameter(classType, "c");
Expression property = Expression.Property(param, propAttr.prop.Name);
LambdaExpression lambdaExpression = Expression.Lambda(property, true,
new ParameterExpression[]
{param});
DecimalPropertyConfiguration decimalConfig;
if (propAttr.prop.PropertyType.IsGenericType && propAttr.prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
MethodInfo methodInfo = entityConfig.GetType().GetMethods().Where(p => p.Name == "Property").ToList()[7];
decimalConfig = methodInfo.Invoke(entityConfig, new[] { lambdaExpression }) as DecimalPropertyConfiguration;
}
else
{
MethodInfo methodInfo = entityConfig.GetType().GetMethods().Where(p => p.Name == "Property").ToList()[6];
decimalConfig = methodInfo.Invoke(entityConfig, new[] { lambdaExpression }) as DecimalPropertyConfiguration;
}
decimalConfig.HasPrecision(propAttr.attr.Precision, propAttr.attr.Scale);
}
}
}
ilk bölüm modeldeki tüm sınıfları elde etmektir (benim özel özniteliği bu derlemede tanımlanır, bu yüzden modelle derlemeyi almak için kullanılır)
ikinci foreach özel öznitelik ve özniteliğin kendisi ile bu sınıftaki tüm özellikleri alır, böylece hassasiyet ve ölçek verilerini alabilirim
ondan sonra aramam gerek
modelBuilder.Entity<MODEL_CLASS>().Property(c=> c.PROPERTY_NAME).HasPrecision(PRECISION,SCALE);
bu yüzden yansıma ile modelBuilder.Entity () çağırmak ve entityConfig değişkeninde saklamak sonra "c => c.PROPERTY_NAME" lambda ifade oluşturmak
Bundan sonra, ondalık sıfırlanabilir ise
Property(Expression<Func<TStructuralType, decimal?>> propertyExpression)
yöntemi (i dizideki pozisyona göre bu, biliyorum ideal değil, herhangi bir yardım çok takdir edilecektir)
ve boş bırakılmazsa
Property(Expression<Func<TStructuralType, decimal>> propertyExpression)
yöntem.
DecimalPropertyConfiguration i olan HasPrecision yöntemini çağırıyorum.
MethodInfo methodInfo = entityConfig.GetType().GetMethod("Property", new[] { lambdaExpression.GetType() });
doğru aşırı yük almak için kullanın . şimdiye kadar çalışıyor gibi görünüyor.
Kullanılması DecimalPrecisonAttribute
KinSlayerUY gelen Ef6 size (ayar aksine özniteliği bireysel özelliklerini idare edecek bir kongre oluşturabilir DecimalPropertyConvention
olduğu gibi bu cevap tüm ondalık özelliklerini etkileyecektir).
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
public sealed class DecimalPrecisionAttribute : Attribute
{
public DecimalPrecisionAttribute(byte precision, byte scale)
{
Precision = precision;
Scale = scale;
}
public byte Precision { get; set; }
public byte Scale { get; set; }
}
public class DecimalPrecisionAttributeConvention
: PrimitivePropertyAttributeConfigurationConvention<DecimalPrecisionAttribute>
{
public override void Apply(ConventionPrimitivePropertyConfiguration configuration, DecimalPrecisionAttribute attribute)
{
if (attribute.Precision < 1 || attribute.Precision > 38)
{
throw new InvalidOperationException("Precision must be between 1 and 38.");
}
if (attribute.Scale > attribute.Precision)
{
throw new InvalidOperationException("Scale must be between 0 and the Precision value.");
}
configuration.HasPrecision(attribute.Precision, attribute.Scale);
}
}
Sonra DbContext
:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(new DecimalPrecisionAttributeConvention());
}
Precision
, üst sınırı 28'e ayarlamanız önerilir (böylece > 28
durumunuzda). MSDN belgelerine göre System.Decimal
, yalnızca maksimum 28-29 basamaklı hassasiyeti temsil edebilir ( msdn.microsoft.com/en-us/library/364x0z75.aspx ). Ayrıca, öznitelik Scale
olarak bildirilir byte
, yani önkoşulunuz attribute.Scale < 0
gereksizdir.
System.Decimal
değil. Bu nedenle, üst sınır ön koşulunu 28'den büyük herhangi bir şeye ayarlamak mantıklı değildir; System.Decimal
Görünüşe göre bu kadar büyük sayıları temsil edemez. Ayrıca, bu özniteliğin SQL Server dışındaki veri sağlayıcıları için yararlı olduğunu unutmayın. Örneğin, PostgreSQL'in numeric
türü 131072 basamağa kadar hassasiyeti destekler.
decimal(38,9)
sütuna sahip olmak mutlu olacak, System.Decimal.MaxValue
ancak bir decimal(28,9)
sütun olmayacaktır. Hassasiyeti sadece 28 ile sınırlamak için bir neden yoktur.
Görünüşe göre, DbContext.OnModelCreating () yöntemini geçersiz kılabilir ve hassasiyeti şu şekilde yapılandırabilirsiniz:
protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>().Property(product => product.Price).Precision = 10;
modelBuilder.Entity<Product>().Property(product => product.Price).Scale = 2;
}
Ama bu fiyat ile ilgili tüm özellikleri ile yapmak zorunda oldukça sıkıcı bir kod, bu yüzden bu ile geldi:
protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
{
var properties = new[]
{
modelBuilder.Entity<Product>().Property(product => product.Price),
modelBuilder.Entity<Order>().Property(order => order.OrderTotal),
modelBuilder.Entity<OrderDetail>().Property(detail => detail.Total),
modelBuilder.Entity<Option>().Property(option => option.Price)
};
properties.ToList().ForEach(property =>
{
property.Precision = 10;
property.Scale = 2;
});
base.OnModelCreating(modelBuilder);
}
Temel uygulama hiçbir şey yapmasa bile, bir yöntemi geçersiz kıldığınızda temel yöntemi çağırmanız iyi bir uygulamadır.
Güncelleme: Bu makale de çok yardımcı oldu.
base.OnModelCreating(modelBuilder);
gerekli olduğunu düşünmüyorum . VS'deki DbContext meta verilerinden: The default implementation of this method does nothing, but it can be overridden in a derived class such that the model can be further configured before it is locked down.
Entity Framework Ver 6 (Alpha, rc1), Özel Kurallar olarak adlandırılan bir şeye sahiptir . Ondalık duyarlığı ayarlamak için:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Properties<decimal>().Configure(config => config.HasPrecision(18, 4));
}
Referans:
[Column(TypeName = "decimal(18,2)")]
bu, burada açıklandığı gibi EF Core kodu ilk geçişleriyle çalışır .
The store type 'decimal(18,2)' could not be found in the SqlServer provider manifest
bu kod satırı aynı şeyi başarmanın daha kolay bir yolu olabilir:
public class ProductConfiguration : EntityTypeConfiguration<Product>
{
public ProductConfiguration()
{
this.Property(m => m.Price).HasPrecision(10, 2);
}
}
- EF CORE İÇİN - ile System.ComponentModel.DataAnnotations kullanarak;
kullanım [Column
( TypeName
= "decimal
( hassasiyet , ölçek )")]
Hassasiyet = Kullanılan toplam karakter sayısı
Ölçek = Noktadan sonraki toplam sayı. (kafası karışması kolay)
Örnek :
public class Blog
{
public int BlogId { get; set; }
[Column(TypeName = "varchar(200)")]
public string Url { get; set; }
[Column(TypeName = "decimal(5, 2)")]
public decimal Rating { get; set; }
}
Daha fazla ayrıntı burada: https://docs.microsoft.com/tr-tr/ef/core/modeling/relational/data-types
EF6'da
modelBuilder.Properties()
.Where(x => x.GetCustomAttributes(false).OfType<DecimalPrecisionAttribute>().Any())
.Configure(c => {
var attr = (DecimalPrecisionAttribute)c.ClrPropertyInfo.GetCustomAttributes(typeof (DecimalPrecisionAttribute), true).FirstOrDefault();
c.HasPrecision(attr.Precision, attr.Scale);
});
EF'e her zaman OnModelCreating işlevindeki Context sınıfındaki kurallarla bunu yapmasını söyleyebilirsiniz:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// <... other configurations ...>
// modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
// modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
// modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
// Configure Decimal to always have a precision of 18 and a scale of 4
modelBuilder.Conventions.Remove<DecimalPropertyConvention>();
modelBuilder.Conventions.Add(new DecimalPropertyConvention(18, 4));
base.OnModelCreating(modelBuilder);
}
Bu yalnızca Code First EF fyi için geçerlidir ve db ile eşlenen tüm ondalık türler için geçerlidir.
Remove<DecimalPropertyConvention>();
Önce gelene kadar çalışma değildi Add(new DecimalPropertyConvention(18, 4));
. Bence sadece otomatik olarak geçersiz kılmamak garip.
kullanma
System.ComponentModel.DataAnnotations;
Bu özelliği modelinize yerleştirebilirsiniz:
[DataType("decimal(18,5)")]
Varlık Veri Modeli'nin MSDN yüzü hakkında daha fazla bilgi bulabilirsiniz. http://msdn.microsoft.com/en-us/library/ee382834.aspx Tam önerilir.
EntityFrameworkCore 3.1.3 için gerçek:
OnModelCreating'de bazı çözümler:
var fixDecimalDatas = new List<Tuple<Type, Type, string>>();
foreach (var entityType in builder.Model.GetEntityTypes())
{
foreach (var property in entityType.GetProperties())
{
if (Type.GetTypeCode(property.ClrType) == TypeCode.Decimal)
{
fixDecimalDatas.Add(new Tuple<Type, Type, string>(entityType.ClrType, property.ClrType, property.GetColumnName()));
}
}
}
foreach (var item in fixDecimalDatas)
{
builder.Entity(item.Item1).Property(item.Item2, item.Item3).HasColumnType("decimal(18,4)");
}
//custom decimal nullable:
builder.Entity<SomePerfectEntity>().Property(x => x.IsBeautiful).HasColumnType("decimal(18,4)");
KinSlayerUY'nin özel özelliği benim için iyi çalıştı ancak ComplexTypes ile ilgili sorunlar yaşadım. Özellik kodundaki varlıklar olarak eşleniyorlardı, bu nedenle bir ComplexType olarak eşlenemediler.
Bu nedenle buna izin vermek için kodu genişletti:
public static void OnModelCreating(DbModelBuilder modelBuilder)
{
foreach (Type classType in from t in Assembly.GetAssembly(typeof(DecimalPrecisionAttribute)).GetTypes()
where t.IsClass && t.Namespace == "FA.f1rstval.Data"
select t)
{
foreach (var propAttr in classType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.GetCustomAttribute<DecimalPrecisionAttribute>() != null).Select(
p => new { prop = p, attr = p.GetCustomAttribute<DecimalPrecisionAttribute>(true) }))
{
ParameterExpression param = ParameterExpression.Parameter(classType, "c");
Expression property = Expression.Property(param, propAttr.prop.Name);
LambdaExpression lambdaExpression = Expression.Lambda(property, true,
new ParameterExpression[] { param });
DecimalPropertyConfiguration decimalConfig;
int MethodNum;
if (propAttr.prop.PropertyType.IsGenericType && propAttr.prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
MethodNum = 7;
}
else
{
MethodNum = 6;
}
//check if complextype
if (classType.GetCustomAttribute<ComplexTypeAttribute>() != null)
{
var complexConfig = modelBuilder.GetType().GetMethod("ComplexType").MakeGenericMethod(classType).Invoke(modelBuilder, null);
MethodInfo methodInfo = complexConfig.GetType().GetMethods().Where(p => p.Name == "Property").ToList()[MethodNum];
decimalConfig = methodInfo.Invoke(complexConfig, new[] { lambdaExpression }) as DecimalPropertyConfiguration;
}
else
{
var entityConfig = modelBuilder.GetType().GetMethod("Entity").MakeGenericMethod(classType).Invoke(modelBuilder, null);
MethodInfo methodInfo = entityConfig.GetType().GetMethods().Where(p => p.Name == "Property").ToList()[MethodNum];
decimalConfig = methodInfo.Invoke(entityConfig, new[] { lambdaExpression }) as DecimalPropertyConfiguration;
}
decimalConfig.HasPrecision(propAttr.attr.Precision, propAttr.attr.Scale);
}
}
}
@ Mark007, DbContext DbSet <> özelliklerine binmek için tür seçim ölçütlerini değiştirdim. Bu daha güvenli olduğunu düşünüyorum çünkü verilen ad alanında model tanımının bir parçası olmamalı ya da varlık olmayan sınıflara sahip olduğunuz zamanlar vardır. Veya varlıklarınız ayrı ad alanlarında veya ayrı montajlarda bulunabilir ve bir kez Bağlam'a çekilebilir.
Ayrıca, olası olmasa da, yöntem tanımlarının sırasına güvenmenin güvenli olduğunu düşünmüyorum, bu yüzden onları Parametre listesiyle çıkarmak daha iyidir. (.GetTypeMethods (), yeni TypeInfo paradigmasıyla çalışmak için oluşturduğum ve yöntemler ararken sınıf hiyerarşilerini düzleştirebilen bir uzantı yöntemidir).
OnModelCreating'in bu yönteme delege ettiğini unutmayın:
private void OnModelCreatingSetDecimalPrecisionFromAttribute(DbModelBuilder modelBuilder)
{
foreach (var iSetProp in this.GetType().GetTypeProperties(true))
{
if (iSetProp.PropertyType.IsGenericType
&& (iSetProp.PropertyType.GetGenericTypeDefinition() == typeof(IDbSet<>) || iSetProp.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>)))
{
var entityType = iSetProp.PropertyType.GetGenericArguments()[0];
foreach (var propAttr in entityType
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Select(p => new { prop = p, attr = p.GetCustomAttribute<DecimalPrecisionAttribute>(true) })
.Where(propAttr => propAttr.attr != null))
{
var entityTypeConfigMethod = modelBuilder.GetType().GetTypeInfo().DeclaredMethods.First(m => m.Name == "Entity");
var entityTypeConfig = entityTypeConfigMethod.MakeGenericMethod(entityType).Invoke(modelBuilder, null);
var param = ParameterExpression.Parameter(entityType, "c");
var lambdaExpression = Expression.Lambda(Expression.Property(param, propAttr.prop.Name), true, new ParameterExpression[] { param });
var propertyConfigMethod =
entityTypeConfig.GetType()
.GetTypeMethods(true, false)
.First(m =>
{
if (m.Name != "Property")
return false;
var methodParams = m.GetParameters();
return methodParams.Length == 1 && methodParams[0].ParameterType == lambdaExpression.GetType();
}
);
var decimalConfig = propertyConfigMethod.Invoke(entityTypeConfig, new[] { lambdaExpression }) as DecimalPropertyConfiguration;
decimalConfig.HasPrecision(propAttr.attr.Precision, propAttr.attr.Scale);
}
}
}
}
public static IEnumerable<MethodInfo> GetTypeMethods(this Type typeToQuery, bool flattenHierarchy, bool? staticMembers)
{
var typeInfo = typeToQuery.GetTypeInfo();
foreach (var iField in typeInfo.DeclaredMethods.Where(fi => staticMembers == null || fi.IsStatic == staticMembers))
yield return iField;
//this bit is just for StaticFields so we pass flag to flattenHierarchy and for the purpose of recursion, restrictStatic = false
if (flattenHierarchy == true)
{
var baseType = typeInfo.BaseType;
if ((baseType != null) && (baseType != typeof(object)))
{
foreach (var iField in baseType.GetTypeMethods(true, staticMembers))
yield return iField;
}
}
}
[Column(TypeName = "decimal(18,4)")]
ondalık özellikleriniz için öznitelik kullanmaktır