Précision décimale et échelle dans le code EF en premier

J’expérimente cette approche basée sur le code, mais je découvre maintenant qu’une propriété de type System.Decimal est associée à une colonne SQL de type décimal (18, 0).

Comment définir la précision de la colonne de firebase database?

La réponse de Dave Van den Eynde est maintenant dépassée. Il y a 2 changements importants, à partir de EF 4.1, la classe ModelBuilder est maintenant DbModelBuilder et il existe maintenant une méthode DecimalPropertyConfiguration.HasPrecision qui a une signature:

public DecimalPropertyConfiguration HasPrecision( byte precision, byte scale ) 

où précision est le nombre total de chiffres que la firebase database va stocker, quel que soit le point décimal et l’échelle est le nombre de décimales qu’il va stocker.

Par conséquent, il n’est pas nécessaire de parcourir les propriétés comme indiqué, mais on peut simplement appeler depuis

 public class EFDbContext : DbContext { protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder) { modelBuilder.Entity().Property(object => object.property).HasPrecision(12, 10); base.OnModelCreating(modelBuilder); } } 

Si vous souhaitez définir la précision de toutes les decimals dans EF6, vous pouvez remplacer la convention DecimalPropertyConvention par défaut utilisée dans DbModelBuilder :

 protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove(); modelBuilder.Conventions.Add(new DecimalPropertyConvention(38, 18)); } 

DecimalPropertyConvention par défaut dans EF6 mappe decimal propriétés decimal(18,2) aux colonnes decimal(18,2) .

Si vous souhaitez que les propriétés individuelles aient une précision spécifiée, vous pouvez définir la précision de la propriété de l’entité sur DbModelBuilder :

 protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity().Property(e => e.Value).HasPrecision(38, 18); } 

Ou ajoutez une EntityTypeConfiguration<> pour l’entité qui spécifie la précision:

 protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Configurations.Add(new MyEntityConfiguration()); } internal class MyEntityConfiguration : EntityTypeConfiguration { internal MyEntityConfiguration() { this.Property(e => e.Value).HasPrecision(38, 18); } } 

J’ai passé un bon moment en créant un atsortingbut personnalisé pour cela:

 [AtsortingbuteUsage(AtsortingbuteTargets.Property, Inherited = false, AllowMultiple = false)] public sealed class DecimalPrecisionAtsortingbute : Atsortingbute { public DecimalPrecisionAtsortingbute(byte precision, byte scale) { Precision = precision; Scale = scale; } public byte Precision { get; set; } public byte Scale { get; set; } } 

en l’utilisant comme ça

 [DecimalPrecision(20,10)] public Nullable DeliveryPrice { get; set; } 

et la magie se produit à la création du modèle avec une certaine reflection

 protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder) { foreach (Type classType in from t in Assembly.GetAssembly(typeof(DecimalPrecisionAtsortingbute)).GetTypes() where t.IsClass && t.Namespace == "YOURMODELNAMESPACE" select t) { foreach (var propAttr in classType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.GetCustomAtsortingbute() != null).Select( p => new { prop = p, attr = p.GetCustomAtsortingbute(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); } } } 

la première partie consiste à obtenir toutes les classes dans le modèle (mon atsortingbut personnalisé est défini dans cet assemblage, je l’ai donc utilisé pour obtenir l’assemblage avec le modèle)

le second foreach obtient toutes les propriétés de cette classe avec l’atsortingbut personnalisé et l’atsortingbut lui-même pour que je puisse obtenir les données de précision et d’échelle

après ça je dois appeler

 modelBuilder.Entity().Property(c=> c.PROPERTY_NAME).HasPrecision(PRECISION,SCALE); 

donc j’appelle modelBuilder.Entity () par reflection et le stocke dans la variable entityConfig puis je construis l’expression lambda “c => c.PROPERTY_NAME”

Après cela, si le nombre décimal est nul, j’appelle le

 Property(Expression> propertyExpression) 

méthode (je l’appelle par la position dans le tableau, ce n’est pas idéal je sais, toute aide sera très appréciée)

et si ce n’est pas nullable, j’appelle le

 Property(Expression> propertyExpression) 

méthode.

Ayant la DecimalPropertyConfiguration, j’appelle la méthode HasPrecision.

Apparemment, vous pouvez remplacer la méthode DbContext.OnModelCreating () et configurer la précision comme ceci:

 protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder) { modelBuilder.Entity().Property(product => product.Price).Precision = 10; modelBuilder.Entity().Property(product => product.Price).Scale = 2; } 

Mais ce code est assez fastidieux lorsque vous devez le faire avec toutes vos propriétés liées aux prix, alors je suis venu avec ceci:

  protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder) { var properties = new[] { modelBuilder.Entity().Property(product => product.Price), modelBuilder.Entity().Property(order => order.OrderTotal), modelBuilder.Entity().Property(detail => detail.Total), modelBuilder.Entity 

Il est recommandé d’appeler la méthode de base lorsque vous remplacez une méthode, même si l’implémentation de base ne fait rien.

Mise à jour: Cet article a également été très utile.

En utilisant DecimalPrecisonAtsortingbute de KinSlayerUY, dans EF6, vous pouvez créer une convention qui gérera les propriétés individuelles ayant l’atsortingbut (par opposition à la définition de DecimalPropertyConvention comme dans cette réponse qui affectera toutes les propriétés décimales).

 [AtsortingbuteUsage(AtsortingbuteTargets.Property, Inherited = false, AllowMultiple = false)] public sealed class DecimalPrecisionAtsortingbute : Atsortingbute { public DecimalPrecisionAtsortingbute(byte precision, byte scale) { Precision = precision; Scale = scale; } public byte Precision { get; set; } public byte Scale { get; set; } } public class DecimalPrecisionAtsortingbuteConvention : PrimitivePropertyAtsortingbuteConfigurationConvention { public override void Apply(ConventionPrimitivePropertyConfiguration configuration, DecimalPrecisionAtsortingbute atsortingbute) { if (atsortingbute.Precision < 1 || attribute.Precision > 38) { throw new InvalidOperationException("Precision must be between 1 and 38."); } if (atsortingbute.Scale > atsortingbute.Precision) { throw new InvalidOperationException("Scale must be between 0 and the Precision value."); } configuration.HasPrecision(atsortingbute.Precision, atsortingbute.Scale); } } 

Puis dans votre DbContext :

 protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Add(new DecimalPrecisionAtsortingbuteConvention()); } 

Entity Framework Ver 6 (Alpha, rc1) a quelque chose appelé conventions personnalisées . Pour définir la précision décimale:

 protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Properties().Configure(config => config.HasPrecision(18, 4)); } 

Référence:

cette ligne de code pourrait être un moyen plus simple de réaliser la même chose:

  public class ProductConfiguration : EntityTypeConfiguration { public ProductConfiguration() { this.Property(m => m.Price).HasPrecision(10, 2); } } 

Dans EF6

 modelBuilder.Properties() .Where(x => x.GetCustomAtsortingbutes(false).OfType().Any()) .Configure(c => { var attr = (DecimalPrecisionAtsortingbute)c.ClrPropertyInfo.GetCustomAtsortingbutes(typeof (DecimalPrecisionAtsortingbute), true).FirstOrDefault(); c.HasPrecision(attr.Precision, attr.Scale); }); 

Vous pouvez toujours demander à EF de le faire avec les conventions de la classe Context dans la fonction OnModelCreating, comme suit:

 protected override void OnModelCreating(DbModelBuilder modelBuilder) { // <... other configurations ...> // modelBuilder.Conventions.Remove(); // modelBuilder.Conventions.Remove(); // modelBuilder.Conventions.Remove(); // Configure Decimal to always have a precision of 18 and a scale of 4 modelBuilder.Conventions.Remove(); modelBuilder.Conventions.Add(new DecimalPropertyConvention(18, 4)); base.OnModelCreating(modelBuilder); } 

Cela ne s’applique qu’au code First EF fyi et s’applique à tous les types décimaux mappés à la firebase database.

En utilisant

 System.ComponentModel.DataAnnotations; 

Vous pouvez simplement mettre cet atsortingbut dans votre modèle:

 [DataType("decimal(18,5)")] 

Vous pouvez trouver plus d’informations sur MSDN – facette de Entity Data Model. http://msdn.microsoft.com/en-us/library/ee382834.aspx Full recommandé.

 [Column(TypeName = "decimal(18,2)")] 

cela fonctionnera les premières migrations du code comme décrit ici .

L’atsortingbut personnalisé de KinSlayerUY fonctionnait parfaitement pour moi, mais j’avais des problèmes avec ComplexTypes. Ils étaient mappés en tant qu’entités dans le code d’atsortingbut et ne pouvaient donc pas être mappés en tant que ComplexType.

J’ai donc étendu le code pour permettre cela:

 public static void OnModelCreating(DbModelBuilder modelBuilder) { foreach (Type classType in from t in Assembly.GetAssembly(typeof(DecimalPrecisionAtsortingbute)).GetTypes() where t.IsClass && t.Namespace == "FA.f1rstval.Data" select t) { foreach (var propAttr in classType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.GetCustomAtsortingbute() != null).Select( p => new { prop = p, attr = p.GetCustomAtsortingbute(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() != 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, j’ai modifié les critères de sélection de type pour piloter les propriétés DbSet <> de DbContext. Je pense que c’est plus sûr car il y a des moments où vous avez des classes dans l’espace de noms donné qui ne devraient pas faire partie de la définition du modèle ou ce sont des entités, mais ne sont pas. Ou vos entités peuvent résider dans des espaces de noms ou des assemblys distincts et être regroupées dans un seul contexte.

En outre, même si cela est peu probable, je ne pense pas que l’on puisse se fier à l’ordre des définitions de méthodes, il est donc préférable de les extraire avec la liste par paramètre. (.GetTypeMethods () est une méthode d’extension que j’ai construite pour fonctionner avec le nouveau paradigme TypeInfo et peut aplatir les hiérarchies de classes lors de la recherche de méthodes).

Notez que OnModelCreating délègue à cette méthode:

  private void OnModelCreatingSetDecimalPrecisionFromAtsortingbute(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.GetCustomAtsortingbute(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 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, ressortingctStatic = 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; } } }