264 votes

Précision décimale et l’échelle par EF Code First

J’expérimente avec cette approche code d’abord, mais je suis savoir maintenant qu’une propriété de type System.Decimal obtient le mappage à une colonne sql de type decimal (18, 0).

Comment définir la précision de la colonne de base de données ?

291voto

AlexC Points 3557

La réponse de Dave Van den Eynde est maintenant obsolète. Il y a 2 changements importants, à partir de 4.1 EF à partir de la ModelBuilder classe est maintenant DbModelBuilder et il y a maintenant un DecimalPropertyConfiguration.HasPrecision Méthode qui a une signature:

public DecimalPropertyConfiguration HasPrecision(
byte precision,
byte scale )

où la précision est le nombre total de chiffres de la db va stocker, indépendamment de la position du point décimal de chutes et de l'échelle est le nombre de décimales, il va stocker.

Par conséquent, il n'est pas nécessaire pour itérer sur les propriétés comme indiqué mais le peut seulement être appelée à partir de

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);
   }
}

95voto

kjbartel Points 453

Similaire à la réponse de mxasim, si vous souhaitez définir la précision pour tous `` dans EF6, vous pourriez également faire ce qui suit :

La valeur par défaut dans maps EF6 propriétés à `` colonnes.

81voto

KinSlayerUY Points 351

J'ai passé un agréable moment de la création d'un Attribut Personnalisé pour ceci:

[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; }

}

l'utiliser comme ceci

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

et la magie qui se passe à la création du modèle avec un peu de réflexion

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);
        }
    }
}

la première partie est d'obtenir toutes les classes dans le modèle (mon attribut personnalisé est défini dans cette assemblée, j'ai donc utilisé que pour obtenir de l'assemblée avec le modèle)

le deuxième foreach obtient toutes les propriétés de la classe avec l'attribut personnalisé, et l'attribut lui-même afin que je puisse obtenir la précision et l'échelle des données

après que j'ai appeler

modelBuilder.Entity<MODEL_CLASS>().Property(c=> c.PROPERTY_NAME).HasPrecision(PRECITION,SCALE);

j'appelle donc le modelBuilder.Entité() par la réflexion et la stocker dans la variable entityConfig puis-je construire le "c => c.PROPERTY_NAME" lambda expression

Après, si la décimale est nullable j'appelle la

Property(Expression<Func<TStructuralType, decimal?>> propertyExpression) 

méthode (j'appelle cela par la position dans le tableau, ce n'est pas idéal, je sais, toute aide sera appréciée)

et si ce n'est pas nullable j'appelle la

Property(Expression<Func<TStructuralType, decimal>> propertyExpression)

la méthode.

Avoir la DecimalPropertyConfiguration j'appelle le HasPrecision méthode.

48voto

Dave Van den Eynde Points 8199

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

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;
}

Mais c'est assez fastidieux de code lorsque vous avez à faire avec tous les prix des propriétés, donc j'ai ceci:

    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);
    }

C'est une bonne pratique que vous appelez la méthode de base lorsque vous remplacez une méthode, même si la base de la mise en œuvre ne fait rien.

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

32voto

mxasim Points 656

Entity Framework Ver 6 (Alpha, rc1) a quelque chose qui s'appelle la Coutume des Conventions. Pour définir la précision décimale:

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

Référence:

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X