मैं इस कोड-प्रथम दृष्टिकोण के साथ प्रयोग कर रहा हूं, लेकिन मुझे अब पता चला है कि प्रकार System.Decimal की एक संपत्ति टाइप दशमलव (18, 0) के एक वर्ग कॉलम में मैप की जाती है।
मैं डेटाबेस कॉलम की शुद्धता कैसे निर्धारित करूं?
मैं इस कोड-प्रथम दृष्टिकोण के साथ प्रयोग कर रहा हूं, लेकिन मुझे अब पता चला है कि प्रकार System.Decimal की एक संपत्ति टाइप दशमलव (18, 0) के एक वर्ग कॉलम में मैप की जाती है।
मैं डेटाबेस कॉलम की शुद्धता कैसे निर्धारित करूं?
जवाबों:
डेव वान डेन आईंडी का जवाब अब पुराना हो गया है। EF 4.1 से 2 महत्वपूर्ण परिवर्तन हुए हैं, बाद में ModelBuilder वर्ग DbModelBuilder है और अब एक DecimalPropertyConfiguration.HasPreaches विधि है जिस पर हस्ताक्षर हैं:
public DecimalPropertyConfiguration HasPrecision(
byte precision,
byte scale )
जहाँ सटीकता अंक की कुल संख्या है db स्टोर करेगा, चाहे दशमलव बिंदु कहाँ गिरे और पैमाने दशमलव स्थानों की संख्या है जो इसे संग्रहीत करेगा।
इसलिए दिखाए गए गुणों के माध्यम से पुनरावृति करने की आवश्यकता नहीं है, लेकिन बस से बुलाया जा सकता है
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);
। क्या वह जानबूझकर या सिर्फ आईडीई के बजाय ऑनलाइन टाइपिंग कोड का शिकार था?
यदि आप decimals
EF6 में सभी के लिए सटीक सेट करना चाहते हैं, तो आप इसमें DecimalPropertyConvention
प्रयुक्त डिफ़ॉल्ट सम्मेलन को बदल सकते हैं DbModelBuilder
:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<DecimalPropertyConvention>();
modelBuilder.Conventions.Add(new DecimalPropertyConvention(38, 18));
}
DecimalPropertyConvention
EF6 में डिफ़ॉल्ट स्तंभों के decimal
लिए गुण मैप करता decimal(18,2)
है।
यदि आप केवल व्यक्तिगत गुणों के लिए एक निर्दिष्ट परिशुद्धता चाहते हैं तो आप इकाई की संपत्ति के लिए सटीक सेट कर सकते हैं DbModelBuilder
:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<MyEntity>().Property(e => e.Value).HasPrecision(38, 18);
}
या, EntityTypeConfiguration<>
उस इकाई के लिए जोड़ें जो सटीकता निर्दिष्ट करती है:
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);
}
}
मेरे पास इसके लिए एक कस्टम विशेषता बनाने का अच्छा समय था:
[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; }
}
इस तरह का उपयोग कर
[DecimalPrecision(20,10)]
public Nullable<decimal> DeliveryPrice { get; set; }
और जादू कुछ प्रतिबिंब के साथ मॉडल निर्माण पर होता है
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);
}
}
}
पहला भाग मॉडल में सभी वर्गों को प्राप्त करने के लिए है (मेरी कस्टम विशेषता उस विधानसभा में परिभाषित की गई है, इसलिए मैंने इसका उपयोग मॉडल के साथ विधानसभा प्राप्त करने के लिए किया है)
दूसरी विशेषता के साथ उस वर्ग में सभी गुण प्राप्त हो जाते हैं, और वह विशेषता जिसे मैं स्वयं सटीक और स्केल डेटा प्राप्त कर सकता हूं
उसके बाद मुझे फोन करना होगा
modelBuilder.Entity<MODEL_CLASS>().Property(c=> c.PROPERTY_NAME).HasPrecision(PRECISION,SCALE);
इसलिए मैं प्रतिबिंब द्वारा मॉडलबेल्ट.इंटिटी () को कॉल करता हूं और इसे एंटीकॉनगिग चर में संग्रहीत करता हूं, फिर मैं "c => c.PROPERTY_NAME" लंबो एक्सप्रेशन बनाता हूं
उसके बाद, यदि दशमलव अशक्त है, तो मैं कॉल करता हूं
Property(Expression<Func<TStructuralType, decimal?>> propertyExpression)
विधि (मैं इसे सरणी में स्थिति से कहता हूं, यह आदर्श नहीं है मुझे पता है, किसी भी मदद की बहुत सराहना की जाएगी)
और अगर यह अशक्त नहीं है तो मैं फोन करता हूं
Property(Expression<Func<TStructuralType, decimal>> propertyExpression)
तरीका।
DecimalPropertyConfiguration होने के बाद मैं HasPreults विधि कहता हूं।
MethodInfo methodInfo = entityConfig.GetType().GetMethod("Property", new[] { lambdaExpression.GetType() });
सही अधिभार प्राप्त करने के लिए उपयोग करता हूं । अभी तक तो काम कर रहा है।
का उपयोग करते हुए DecimalPrecisonAttribute
KinSlayerUY से, EF6 में आप एक सम्मेलन जो अलग-अलग प्रॉपर्टी जो विशेषता है (के रूप में स्थापित करने के लिए विरोध संभाल लेंगे बना सकते हैं DecimalPropertyConvention
की तरह इस जवाब जो सभी दशमलव गुणों को प्रभावित करेगा)।
[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);
}
}
फिर अपने में DbContext
:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(new DecimalPrecisionAttributeConvention());
}
Precision
, तो मैं ऊपरी 28 को बाध्य करने की सलाह देता हूं (इसलिए > 28
आपकी स्थिति में)। MSDN प्रलेखन के अनुसार, System.Decimal
केवल परिशुद्धता के अधिकतम 28-29 अंक का प्रतिनिधित्व कर सकते हैं ( msdn.microsoft.com/en-us/library/364x0z75.aspx )। इसके अलावा, विशेषता के Scale
रूप में घोषित किया जाता है byte
, जिसका अर्थ है कि आपकी पूर्व शर्त attribute.Scale < 0
अनावश्यक है।
System.Decimal
नहीं है। इसलिए यह 28 से अधिक के लिए ऊपरी बाध्य पूर्व शर्त सेट करने के लिए कोई मतलब नहीं है; System.Decimal
जाहिर है कि बड़ी संख्या का प्रतिनिधित्व नहीं कर सकते। यह भी जान लें कि यह विशेषता SQL सर्वर के अलावा डेटा प्रदाताओं के लिए उपयोगी है। उदाहरण के लिए, PostgreSQL का numeric
प्रकार परिशुद्धता के 131072 अंकों तक का समर्थन करता है।
decimal(38,9)
कॉलम होने से खुशी होगी System.Decimal.MaxValue
लेकिन एक decimal(28,9)
कॉलम नहीं होगा। परिशुद्धता को केवल 28 तक सीमित करने का कोई कारण नहीं है।
जाहिरा तौर पर, आप DbContext.OnModelCreating () विधि को ओवरराइड कर सकते हैं और इस तरह परिशुद्धता को कॉन्फ़िगर कर सकते हैं:
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;
}
लेकिन यह बहुत थकाऊ कोड है जब आपको इसे अपने सभी मूल्य-संबंधित गुणों के साथ करना होता है, तो मैं इसके साथ आया:
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);
}
यह अच्छा अभ्यास है कि जब आप किसी विधि को ओवरराइड करते हैं, तो आधार विधि को कॉल करते हैं, भले ही आधार कार्यान्वयन कुछ भी नहीं करता है।
अद्यतन: यह लेख भी बहुत उपयोगी था।
base.OnModelCreating(modelBuilder);
करना आवश्यक है। VSB में DbContext मेटाडेटा से: 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.
एंटिटी फ्रेमवर्क वेर 6 (अल्फा, आरसी 1) में कस्टम कन्वेंशन नामक कुछ है । दशमलव सटीक सेट करने के लिए:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Properties<decimal>().Configure(config => config.HasPrecision(18, 4));
}
संदर्भ:
[Column(TypeName = "decimal(18,2)")]
यह यहाँ वर्णित के रूप में EF कोर कोड पहले पलायन के साथ काम करेगा ।
The store type 'decimal(18,2)' could not be found in the SqlServer provider manifest
इस कोड लाइन को सरल बनाने का एक सरल तरीका हो सकता है:
public class ProductConfiguration : EntityTypeConfiguration<Product>
{
public ProductConfiguration()
{
this.Property(m => m.Price).HasPrecision(10, 2);
}
}
- एफई कोर के लिए - के साथ System.ComponentModel.DataAnnotations का उपयोग करने के ;
उपयोग [Column
( TypeName
= "decimal
( परिशुद्धता , पैमाने )")]
सटीक = कुल वर्णों की संख्या
स्केल = डॉट के बाद की कुल संख्या। (भ्रमित होने में आसान)
उदाहरण :
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; }
}
अधिक विवरण यहां: https://docs.microsoft.com/en-us/ef/core/modeling/relational/data-tpes
ईएफ 6 में
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 को OnModelCreating फ़ंक्शन में संदर्भ वर्ग में सम्मेलनों के साथ ऐसा करने के लिए कह सकते हैं:
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);
}
यह केवल कोड फर्स्ट EF फी पर लागू होता है और db पर मैप किए गए सभी दशमलव प्रकारों पर लागू होता है।
Remove<DecimalPropertyConvention>();
पहले तक काम नहीं कर रहा था Add(new DecimalPropertyConvention(18, 4));
। मुझे लगता है कि यह अजीब है जो सिर्फ स्वचालित रूप से ओवरराइड नहीं है।
का उपयोग करते हुए
System.ComponentModel.DataAnnotations;
आप बस उस विशेषता को अपने मॉडल में डाल सकते हैं:
[DataType("decimal(18,5)")]
आप MSDN - Entity Data Model के पहलू पर अधिक जानकारी प्राप्त कर सकते हैं। http://msdn.microsoft.com/en-us/library/ee382834.aspx पूर्ण अनुशंसित।
EntityFrameworkCore 3.1.3 के लिए वास्तविक:
OnModelCreating में कुछ समाधान:
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 की कस्टम विशेषता ने मेरे लिए अच्छी तरह से काम किया लेकिन मेरे पास ComplexTypes के साथ समस्याएँ थीं। उन्हें विशेषता कोड में संस्थाओं के रूप में मैप किया जा रहा था, इसलिए उन्हें कॉम्प्लेक्स टाइप के रूप में मैप नहीं किया जा सकता था।
इसलिए मैंने इसके लिए अनुमति देने के लिए कोड बढ़ाया:
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, मैंने DbCettext के DbSet <> गुणों की सवारी करने के लिए चयन के प्रकार को बदल दिया है। मुझे लगता है कि यह सुरक्षित है क्योंकि कई बार आपके पास दिए गए नेमस्पेस में ऐसी कक्षाएं होती हैं जो मॉडल की परिभाषा का हिस्सा नहीं होनी चाहिए या वे नहीं हैं, लेकिन संस्थाएं नहीं हैं। या आपकी संस्थाएँ अलग-अलग नामस्थान या अलग-अलग विधानसभाओं में निवास कर सकती हैं और एक साथ एक बार प्रसंग में खींची जा सकती हैं।
इसके अलावा, भले ही संभावना नहीं है, मुझे नहीं लगता कि विधि परिभाषाओं के आदेश पर भरोसा करना सुरक्षित है, इसलिए उन्हें व्यास सूची से बाहर निकालना बेहतर है। (.GetTypeMethods () एक एक्सटेंशन विधि है जिसे मैंने नए TypeInfo प्रतिमान के साथ काम करने के लिए बनाया है और तरीकों की तलाश में वर्ग पदानुक्रम को समतल कर सकता है)।
ध्यान दें कि OnModelCreating प्रतिनिधियों को इस विधि में:
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)")]
आपके दशमलव गुणों के लिए विशेषता का उपयोग करना है