扩展entity framework core实现默认字符串长度,decimal精度,entity自动注册和配置

来源:互联网 发布:画图软件怎么移动 编辑:程序博客网 时间:2024/05/02 01:45

文章以efcore 2.0.0-preview2.测试验证通过。其他版本不保证使用,但是思路不会差太远。源代码,报道越短,事情越严重!文章越短,内容越精悍!

目标:
1.实现entity的自动发现和mapper设置.
2.默认字符串长度,而不是nvarchar(max).
3.decimal设置精度

实现目标1:继承RelationalModelCustomizer,重写Customize方法。

当然,我们也可以重写dbcontext的OnModelCreating方法,but,我们怎么能这么low呢。必须要用点高级玩意是吧,当然这也是更底层的扩展方式。项目里面有多个dbcontext的话,在这里集中扩展管理比较方便。
在然后,这个RelationalModelCustomizer继承自ModelCustomizer。在联想到efcore未来的版本会支持redis,nosql什么的。到时候估计还回有一个osqlModelCustomizer之类的吧,期待中......

实现目标2、3:继承自CoreConventionSetBuilder类,重写CreateConventionSet方法。

重写CreateConventionSet方法,能拿到关键的ConventionSet对象。这个对象囊括了诸多的约定配置等等。比如maxlengthattribute属性标记,stringlength属性标记,timestamp属性标记,表id的自动发现规则等等等。。。
那,我们增加2个小小的约定:字符串默认长度(StringDefaultLengthConvention),和decimal精度设置attribute(DecimalPrecisionAttributeConvention)及fluntapi方式.

文章的最后附efcore 所有的可替换扩展service。

//servie,DI注入替换.services.AddSingleton<IModelCustomizer, MyRelationalModelCustomizer>();services.AddSingleton<ICoreConventionSetBuilder, MyCoreConventionSetBuilder>();
//实现entity的自动发现和mapper设置

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();    
          //默认字符串长度,而不是nvarchar(max).        //为什么要insert(0,obj),则是因为这个默认规则要最优先处理,如果后续有规则的话就直接覆盖了。        //propertyBuilder.HasMaxLength(32, ConfigurationSource.Convention);        //理论上我指定了规则的级别为.Convention,应该和顺序就没有关系了。but,还没有完成测试,所以我也不知道        conventionSet.PropertyAddedConventions.Insert(0, new StringDefaultLengthConvention());        //decimal设置精度        conventionSet.PropertyAddedConventions.Add(new DecimalPrecisionAttributeConvention());      
            return conventionSet;    }}

下面是StringDefaultLengthConvention和DecimalPrecisionAttributeConvention的实现代码

//字符串默认长度
public class StringDefaultLengthConvention : IPropertyAddedConvention{    
    public InternalPropertyBuilder Apply(InternalPropertyBuilder propertyBuilder)    {      
 if (propertyBuilder.Metadata.ClrType == typeof(string))            propertyBuilder.HasMaxLength(32, ConfigurationSource.Convention);    
     return propertyBuilder;    }}
//attribute方式设置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类型设置精度
/// </summary>
/// <param name="propertyBuilder"></param>/// <param name="precision">精度</param>/// <param name="scale">小数位数</param>public static PropertyBuilder<TProperty> HasPrecision<TProperty>(this PropertyBuilder<TProperty> propertyBuilder, int precision = 18, int scale = 4){    //fluntapi方式设置精度      ((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;}

以上就是实现的代码,就这么几行。嗯,还是挺简单的.

--------------

以下,则是efcore的源代码。展示了如此之多的可扩展。随着DI的运用和微软的开放,嗯。用烂啦,用炸拉(^_^)

//各种规则和约定
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;}
//还是各种规则和约定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(foreignKeyPropertyDiscoveryConvention);    conventionSet.KeyAddedConventions.Add(foreignKeyIndexConvention);    conventionSet.KeyRemovedConventions.Add(foreignKeyPropertyDiscoveryConvention);    conventionSet.KeyRemovedConventions.Add(foreignKeyIndexConvention);    conventionSet.KeyRemovedConventions.Add(keyDiscoveryConvention);  
                   var cascadeDeleteConvention = new CascadeDeleteConvention();    conventionSet.ForeignKeyAddedConventions.Add(new ForeignKeyAttributeConvention(Dependencies.TypeMapper));    conventionSet.ForeignKeyAddedConventions.Add(foreignKeyPropertyDiscoveryConvention);    conventionSet.ForeignKeyAddedConventions.Add(keyDiscoveryConvention);    conventionSet.ForeignKeyAddedConventions.Add(valueGeneratorConvention );    conventionSet.ForeignKeyAddedConventions.Add(cascadeDeleteConvention);    conventionSet.ForeignKeyAddedConventions.Add(foreignKeyIndexConvention);    conventionSet.ForeignKeyRemovedConventions.Add(keyDiscoveryConvention);    conventionSet.ForeignKeyRemovedConventions.Add(valueGeneratorConvention );    conventionSet.ForeignKeyRemovedConventions.Add(foreignKeyIndexConvention);    conventionSet.ForeignKeyUniquenessChangedConventions.Add(foreignKeyPropertyDiscoveryConvention);    conventionSet.ForeignKeyUniquenessChangedConventions.Add(foreignKeyIndexConvention);    conventionSet.ForeignKeyOwnershipChangedConventions.Add(new NavigationEagerLoadingConvention());    conventionSet.ModelBuiltConventions.Add(new ModelCleanupConvention());    conventionSet.ModelBuiltConventions.Add(keyAttributeConvention);    conventionSet.ModelBuiltConventions.Add(new IgnoredMembersValidationConvention());    conventionSet.ModelBuiltConventions.Add(new PropertyMappingValidationConvention(Dependencies.TypeMapper));    conventionSet.ModelBuiltConventions.Add(new RelationshipValidationConvention());    conventionSet.ModelBuiltConventions.Add(foreignKeyPropertyDiscoveryConvention);    conventionSet.NavigationAddedConventions.Add(backingFieldConvention);    conventionSet.NavigationAddedConventions.Add(new RequiredNavigationAttributeConvention());    conventionSet.NavigationAddedConventions.Add(inversePropertyAttributeConvention);    conventionSet.NavigationAddedConventions.Add(foreignKeyPropertyDiscoveryConvention);    conventionSet.NavigationAddedConventions.Add(relationshipDiscoveryConvention);    conventionSet.NavigationRemovedConventions.Add(relationshipDiscoveryConvention);    conventionSet.IndexAddedConventions.Add(foreignKeyIndexConvention);    conventionSet.IndexRemovedConventions.Add(foreignKeyIndexConvention);    conventionSet.IndexUniquenessChangedConventions.Add(foreignKeyIndexConvention);    conventionSet.PropertyNullabilityChangedConventions.Add(cascadeDeleteConvention);    conventionSet.PrincipalEndChangedConventions.Add(foreignKeyPropertyDiscoveryConvention);    conventionSet.PropertyFieldChangedConventions.Add(keyDiscoveryConvention);    conventionSet.PropertyFieldChangedConventions.Add(foreignKeyPropertyDiscoveryConvention);    conventionSet.PropertyFieldChangedConventions.Add(keyAttributeConvention);    conventionSet.PropertyFieldChangedConventions.Add(concurrencyCheckAttributeConvention);    conventionSet.PropertyFieldChangedConventions.Add(databaseGeneratedAttributeConvention);    conventionSet.PropertyFieldChangedConventions.Add(requiredPropertyAttributeConvention);    conventionSet.PropertyFieldChangedConventions.Add(maxLengthAttributeConvention);    conventionSet.PropertyFieldChangedConventions.Add(stringLengthAttributeConvention);    conventionSet.PropertyFieldChangedConventions.Add(timestampAttributeConvention);        return conventionSet;}

我就是所有的可替换service啦。不要眼花有点多!,找着合适的用起来!

serviceCollection.AsQueryable()    .Where(p => p.ServiceType.ToString().StartsWith("Microsoft.EntityFrameworkCore"))    .Each(sd =>{    Console.WriteLine($"{sd.Lifetime.ToString().PadRight(15, ' ')}{sd.ServiceType.FullName}");});

原文地址:http://www.cnblogs.com/calvinK/p/7234872.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

阅读全文
0 0
原创粉丝点击