文章以efcore 2.0.0-preview2.測試驗證通過。其他版本不保證使用,但是思路不會差太遠(yuǎn)。源代碼,報道越短,事情越嚴(yán)重!文章越短,內(nèi)容越精悍!
目標(biāo):
1.實現(xiàn)entity的自動發(fā)現(xiàn)和mapper設(shè)置.
2.默認(rèn)字符串長度,而不是nvarchar(max).
3.decimal設(shè)置精度
實現(xiàn)目標(biāo)1:繼承RelationalModelCustomizer,重寫Customize方法。
當(dāng)然,我們也可以重寫dbcontext的OnModelCreating方法,but,我們怎么能這么low呢。必須要用點高級玩意是吧,當(dāng)然這也是更底層的擴(kuò)展方式。項目里面有多個dbcontext的話,在這里集中擴(kuò)展管理比較方便。
在然后,這個RelationalModelCustomizer繼承自ModelCustomizer。在聯(lián)想到efcore未來的版本會支持redis,nosql什么的。到時候估計還回有一個osqlModelCustomizer之類的吧,期待中......
實現(xiàn)目標(biāo)2、3:繼承自CoreConventionSetBuilder類,重寫CreateConventionSet方法。
重寫CreateConventionSet方法,能拿到關(guān)鍵的ConventionSet對象。這個對象囊括了諸多的約定配置等等。比如maxlengthattribute屬性標(biāo)記,stringlength屬性標(biāo)記,timestamp屬性標(biāo)記,表id的自動發(fā)現(xiàn)規(guī)則等等等。。。
那,我們增加2個小小的約定:字符串默認(rèn)長度(StringDefaultLengthConvention),和decimal精度設(shè)置attribute(DecimalPrecisionAttributeConvention)及fluntapi方式.
文章的最后附efcore 所有的可替換擴(kuò)展service。
//servie,DI注入替換.services.AddSingleton<IModelCustomizer, MyRelationalModelCustomizer>(); services.AddSingleton<ICoreConventionSetBuilder, MyCoreConventionSetBuilder>();//實現(xiàn)entity的自動發(fā)現(xiàn)和mapper設(shè)置public class MyRelationalModelCustomizer : RelationalModelCustomizer{ public MyRelationalModelCustomizer(ModelCustomizerDependencies dependencies) : base(dependencies){} public override void Customize(ModelBuilder modelBuilder, DbContext dbContext) { base.Customize(modelBuilder, dbContext); var sp = (IInfrastructure<IServiceProvider>)dbContext; var dbOptions = sp.Instance.GetServices<DbContextOptions>(); foreach (var item in dbOptions) { if (item.ContextType == dbContext.GetType()) ConfigureDbContextEntityService.Configure(modelBuilder, item, dbContext); } } }public class MyCoreConventionSetBuilder : CoreConventionSetBuilder{ public MyCoreConventionSetBuilder(CoreConventionSetBuilderDependencies dependencies) : base(dependencies){} public override ConventionSet CreateConventionSet() { var conventionSet = base.CreateConventionSet(); //默認(rèn)字符串長度,而不是nvarchar(max). //為什么要insert(0,obj),則是因為這個默認(rèn)規(guī)則要最優(yōu)先處理,如果后續(xù)有規(guī)則的話就直接覆蓋了。 //propertyBuilder.HasMaxLength(32, ConfigurationSource.Convention); //理論上我指定了規(guī)則的級別為.Convention,應(yīng)該和順序就沒有關(guān)系了。but,還沒有完成測試,所以我也不知道 conventionSet.PropertyAddedConventions.Insert(0, new StringDefaultLengthConvention()); //decimal設(shè)置精度 conventionSet.PropertyAddedConventions.Add(new DecimalPrecisionAttributeConvention()); return conventionSet; } }
下面是StringDefaultLengthConvention和DecimalPrecisionAttributeConvention的實現(xiàn)代碼
//字符串默認(rèn)長度public class StringDefaultLengthConvention : IPropertyAddedConvention { public InternalPropertyBuilder Apply(InternalPropertyBuilder propertyBuilder) { if (propertyBuilder.Metadata.ClrType == typeof(string)) propertyBuilder.HasMaxLength(32, ConfigurationSource.Convention); return propertyBuilder; } }//attribute方式設(shè)置decimal精度public class DecimalPrecisionAttributeConvention : PropertyAttributeConvention<DecimalPrecisionAttribute> { public override InternalPropertyBuilder Apply(InternalPropertyBuilder propertyBuilder, DecimalPrecisionAttribute attribute, MemberInfo clrMember) { if (propertyBuilder.Metadata.ClrType == typeof(decimal)) propertyBuilder.HasPrecision(attribute.Precision, attribute.Scale); return propertyBuilder; }/// <summary>/// decimal類型設(shè)置精度/// </summary>/// <param name="propertyBuilder"></param>/// <param name="precision">精度</param>/// <param name="scale">小數(shù)位數(shù)</param>public static PropertyBuilder<TProperty> HasPrecision<TProperty>(this PropertyBuilder<TProperty> propertyBuilder, int precision = 18, int scale = 4) { //fluntapi方式設(shè)置精度 ((IInfrastructure<InternalPropertyBuilder>)propertyBuilder).Instance.HasPrecision(precision, scale); return propertyBuilder; }public static InternalPropertyBuilder HasPrecision(this InternalPropertyBuilder propertyBuilder, int precision, int scale){ propertyBuilder.Relational(ConfigurationSource.Explicit).HasColumnType($"decimal({precision},{scale})"); return propertyBuilder; }
以上就是實現(xiàn)的代碼,就這么幾行。嗯,還是挺簡單的.
--------------
以下,則是efcore的源代碼。展示了如此之多的可擴(kuò)展。隨著DI的運用和微軟的開放,嗯。用爛啦,用炸拉(^_^)
//各種規(guī)則和約定public virtual ConventionSet AddConventions(ConventionSet conventionSet){ ValueGeneratorConvention valueGeneratorConvention = new RelationalValueGeneratorConvention(); ReplaceConvention(conventionSet.BaseEntityTypeChangedConventions, valueGeneratorConvention); ReplaceConvention(conventionSet.PrimaryKeyChangedConventions, valueGeneratorConvention); ReplaceConvention(conventionSet.ForeignKeyAddedConventions, valueGeneratorConvention); ReplaceConvention(conventionSet.ForeignKeyRemovedConventions, valueGeneratorConvention); var relationalColumnAttributeConvention = new RelationalColumnAttributeConvention(); conventionSet.PropertyAddedConventions.Add(relationalColumnAttributeConvention); var sharedTableConvention = new SharedTableConvention(); conventionSet.EntityTypeAddedConventions.Add(new RelationalTableAttributeConvention()); conventionSet.EntityTypeAddedConventions.Add(sharedTableConvention); conventionSet.BaseEntityTypeChangedConventions.Add(new DiscriminatorConvention()); conventionSet.BaseEntityTypeChangedConventions.Add( new TableNameFromDbSetConvention(Dependencies.Context?.Context, Dependencies.SetFinder)); conventionSet.EntityTypeAnnotationChangedConventions.Add(sharedTableConvention); conventionSet.PropertyFieldChangedConventions.Add(relationalColumnAttributeConvention); conventionSet.PropertyAnnotationChangedConventions.Add((RelationalValueGeneratorConvention)valueGeneratorConvention); conventionSet.ForeignKeyUniquenessChangedConventions.Add(sharedTableConvention); conventionSet.ForeignKeyOwnershipChangedConventions.Add(sharedTableConvention); conventionSet.ModelBuiltConventions.Add(new RelationalTypeMappingConvention(Dependencies.TypeMapper)); conventionSet.ModelBuiltConventions.Add(sharedTableConvention); conventionSet.ModelAnnotationChangedConventions.Add(new RelationalDbFunctionConvention()); return conventionSet; }
//還是各種規(guī)則和約定public virtual ConventionSet CreateConventionSet(){ var conventionSet = new ConventionSet(); var propertyDiscoveryConvention = new PropertyDiscoveryConvention(Dependencies.TypeMapper); var keyDiscoveryConvention = new KeyDiscoveryConvention(); var inversePropertyAttributeConvention = new InversePropertyAttributeConvention(Dependencies.TypeMapper); var relationshipDiscoveryConvention = new RelationshipDiscoveryConvention(Dependencies.TypeMapper); conventionSet.EntityTypeAddedConventions.Add(new NotMappedEntityTypeAttributeConvention()); conventionSet.EntityTypeAddedConventions.Add(new NotMappedMemberAttributeConvention()); conventionSet.EntityTypeAddedConventions.Add(new BaseTypeDiscoveryConvention()); conventionSet.EntityTypeAddedConventions.Add(propertyDiscoveryConvention); conventionSet.EntityTypeAddedConventions.Add(keyDiscoveryConvention); conventionSet.EntityTypeAddedConventions.Add(inversePropertyAttributeConvention); conventionSet.EntityTypeAddedConventions.Add(relationshipDiscoveryConvention); conventionSet.EntityTypeAddedConventions.Add(new DerivedTypeDiscoveryConvention()); conventionSet.EntityTypeIgnoredConventions.Add(inversePropertyAttributeConvention); var foreignKeyIndexConvention = new ForeignKeyIndexConvention(); var valueGeneratorConvention = new ValueGeneratorConvention(); conventionSet.BaseEntityTypeChangedConventions.Add(propertyDiscoveryConvention); conventionSet.BaseEntityTypeChangedConventions.Add(keyDiscoveryConvention); conventionSet.BaseEntityTypeChangedConventions.Add(inversePropertyAttributeConvention); conventionSet.BaseEntityTypeChangedConventions.Add(relationshipDiscoveryConvention); conventionSet.BaseEntityTypeChangedConventions.Add(foreignKeyIndexConvention); conventionSet.BaseEntityTypeChangedConventions.Add(valueGeneratorConvention ); // An ambiguity might have been resolved conventionSet.EntityTypeMemberIgnoredConventions.Add(inversePropertyAttributeConvention); conventionSet.EntityTypeMemberIgnoredConventions.Add(relationshipDiscoveryConvention); var keyAttributeConvention = new KeyAttributeConvention(); var foreignKeyPropertyDiscoveryConvention = new ForeignKeyPropertyDiscoveryConvention(); var backingFieldConvention = new BackingFieldConvention(); var concurrencyCheckAttributeConvention = new ConcurrencyCheckAttributeConvention(); var databaseGeneratedAttributeConvention = new DatabaseGeneratedAttributeConvention(); var requiredPropertyAttributeConvention = new RequiredPropertyAttributeConvention(); var maxLengthAttributeConvention = new MaxLengthAttributeConvention(); var stringLengthAttributeConvention = new StringLengthAttributeConvention(); var timestampAttributeConvention = new TimestampAttributeConvention(); conventionSet.PropertyAddedConventions.Add(backingFieldConvention); conventionSet.PropertyAddedConventions.Add(concurrencyCheckAttributeConvention); conventionSet.PropertyAddedConventions.Add(databaseGeneratedAttributeConvention); conventionSet.PropertyAddedConventions.Add(requiredPropertyAttributeConvention); conventionSet.PropertyAddedConventions.Add(maxLengthAttributeConvention); conventionSet.PropertyAddedConventions.Add(stringLengthAttributeConvention); conventionSet.PropertyAddedConventions.Add(timestampAttributeConvention); conventionSet.PropertyAddedConventions.Add(keyDiscoveryConvention); conventionSet.PropertyAddedConventions.Add(foreignKeyPropertyDiscoveryConvention); conventionSet.PropertyAddedConventions.Add(keyAttributeConvention); conventionSet.PrimaryKeyChangedConventions.Add(valueGeneratorConvention); conventionSet.KeyAddedConventions.Add(foreignKeyPropertyDiscoveryConventi
http://www.cnblogs.com/calvinK/p/7234872.html