首页 > 其他 > 详细

EntityFrameworkCore中的OnModelCreating

时间:2019-04-02 13:53:56      阅读:199      评论:0      收藏:0      [点我收藏+]

  在我们使用EntityFrameworkCore作为数据库ORM框架的时候,不可避免的要重载DbContext中的一个虚方法OnModelCreating,那么这个方法到底是做什么的?到底有哪些作用呢?带着这些问题我们来看看在EntityFrameworkCore到底该如何使用OnModelCreating这个方法,首先我们来看看Microsoft.EntityFrameworkCore命名空间下面的DbContext中关于OnModelCreating的定义及注释。

/// <summary>
    ///     Override this method to further configure the model that was discovered by convention from the entity types
    ///     exposed in <see cref="T:Microsoft.EntityFrameworkCore.DbSet`1" /> properties on your derived context. The resulting model may be cached
    ///     and re-used for subsequent instances of your derived context.
    /// </summary>
    /// <remarks>
    ///     If a model is explicitly set on the options for this context (via <see cref="M:Microsoft.EntityFrameworkCore.DbContextOptionsBuilder.UseModel(Microsoft.EntityFrameworkCore.Metadata.IModel)" />)
    ///     then this method will not be run.
    /// </remarks>
    /// <param name="modelBuilder">
    ///     The builder being used to construct the model for this context. Databases (and other extensions) typically
    ///     define extension methods on this object that allow you to configure aspects of the model that are specific
    ///     to a given database.
    /// </param>
    protected internal virtual void OnModelCreating(ModelBuilder modelBuilder)
    {
    }

  按照官方的解释:在完成对派生上下文的模型的初始化后,并在该模型已锁定并用于初始化上下文之前,将调用此方法。 虽然此方法的默认实现不执行任何操作,但可在派生类中重写此方法,这样便能在锁定模型之前对其进行进一步的配置。通常,在创建派生上下文的第一个实例时仅调用此方法一次。 然后将缓存该上下文的模型,并且该模型适用于应用程序域中的上下文的所有后续实例。 通过在给定的 ModelBuidler 上设置 ModelCaching 属性可禁用此缓存,但注意这样做会大大降低性能。 通过直接使用 DbModelBuilder 和 DbContextFactory 类来提供对缓存的更多控制。那么这些深度的自定义配置有哪些方面的内容呢?

      一 通过Fluent API配置实体

  这个部分是整个配置的重点,我们能够通过Fluent API来进行各种各样的配置,下面通过一系列的例子来加以说明,这里推荐一篇非常好的文章,这里便不再赘述,这里只讲述之前不同的部分,从而使整篇文章更加完整,如果你对数据库中的关系映射不太清楚,请阅读这篇文章

  A 设置主外键关系

 #region Sales.Basis 主键及关系设定

            modelBuilder.Entity<DealerMarketDptRelation>()
                .HasOne(d => d.MarketingDepartment)
                .WithMany(e => e.DealerMarketDptRelations)
                .HasForeignKey(d => d.MarketId);

            modelBuilder.Entity<Company>()
                .HasOne(c => c.Branch)
                .WithOne(d => d.Company)
                .HasForeignKey<Branch>(d => d.Id);

            modelBuilder.Entity<Company>()
                .HasOne(c => c.Dealer)
                .WithOne(d => d.Company)
                .HasForeignKey<Dealer>(d => d.Id);

            #endregion  

  B  设置索引  

 modelBuilder.Entity<RepairContract>(r => {
                r.HasIndex(p => p.Code);
                r.HasIndex(p => p.Vin);
                r.HasIndex(p => p.DealerCode);
                r.HasIndex(p => p.DealerName);
                r.HasIndex(p => p.CreateTime);
                r.HasIndex(p => p.ModifyTime);
            });

  在查询数据库的时候我们经常需添加索引,在Fluent API中我们可以通过上面的方式来为某一个表添加索引。

  C 设置表级联删除

   #region 设置级联删除行为

            foreach (var foreignKey in modelBuilder.Model.GetEntityTypes().SelectMany(d => d.GetForeignKeys())) {
                foreignKey.DeleteBehavior = DeleteBehavior.Restrict;
            }
            
            #endregion

  D 设置不同数据库专有特性

  由于数据库有多种类型,所以不可避免我们需要针对特定数据库来做一些配置,比如Oracle数据库会限定列名最大为30个字符,有比如有些实体中定义的属性,比如Level可能在Oracle数据库中作为一种关键字,而在另外的数据库系统中则没有这个限制,所以我们通过modelBuilder.Entity<FaultCategoryType>(d => d.Property(p => p.Level).HasColumnName("FLevel"))这种方式来将实体属性名称设置为FLevel,针对这个方面我们也可以在OnModelCreating中统一进行处理。

if (Database.IsOracle()) {
                // Oracle 要求列名不超过30个字符
                modelBuilder.Entity<NotificationInfo>(entity => {
                    entity.Property(e => e.EntityTypeAssemblyQualifiedName)
                        .HasColumnName("EntityTypeAssyQualifiedName");
                });
                modelBuilder.Entity<NotificationSubscriptionInfo>(entity => {
                    entity.Property(e => e.EntityTypeAssemblyQualifiedName)
                        .HasColumnName("EntityTypeAssyQualifiedName");
                });
                modelBuilder.Entity<TenantNotificationInfo>(entity => {
                    entity.Property(e => e.EntityTypeAssemblyQualifiedName)
                        .HasColumnName("EntityTypeAssyQualifiedName");
                });

                // 日志的时间需要精确
                modelBuilder.Entity<AuditLog>(entity => {
                    entity.Property(e => e.ExecutionTime).HasColumnType("TimeStamp");
                });
                modelBuilder.Entity<EntityChange>(entity => {
                    entity.Property(e => e.ChangeTime).HasColumnType("TimeStamp");
                });
                modelBuilder.Entity<EntityChangeSet>(entity => {
                    entity.Property(e => e.CreationTime).HasColumnType("TimeStamp");
                    entity.Property(e => e.ExtensionData).HasMaxLength(int.MaxValue);
                });

                foreach (var entity in modelBuilder.Model.GetEntityTypes()) {
                    if (entity.ClrType == null) continue;
                    if (!entity.ClrType.GetAttributes<TableAttribute>().Any()) {
                        entity.Relational().TableName = entity.ClrType.Name;
                    }
                    foreach (var property in entity.GetProperties().Where(p => p.PropertyInfo != null)){
                        if (property.PropertyInfo.Name.ToUpper().EndsWith("ID") && property.ClrType == typeof(string)) {
                            property.Relational().ColumnType = "CHAR(36)";
                        }
                        else if (property.Name == "RowVersion" &&
                                 (property.ClrType == typeof(DateTime) || property.ClrType == typeof(DateTime?))) {
                            property.Oracle().ColumnType = "TIMESTAMP";
                        }
                        else if (property.ClrType == typeof(decimal) || property.ClrType == typeof(decimal?)) {
                            property.Oracle().ColumnType = "NUMBER(16,4)";
                        }

                    }
                }
                modelBuilder.Entity<ClaimApplyAth>(d => d.Property(p => p.FileId).HasColumnType("VARCHAR2(200)"));
                modelBuilder.Entity<MarketQualityAth>(d => d.Property(p => p.FileId).HasColumnType("VARCHAR2(200)"));
                modelBuilder.Entity<FaultCategoryType>(d => d.Property(p => p.Level).HasColumnName("FLevel"));
            }  

  再比如表中常用的RowVersion字段在Oracle中实体可定义为DateTime类型,而在SQL Server中就只能够定义为byte[ ]这种方式了,所以在使用的时候都可以通过上面的方式来统一进行处理。

/// <summary>
        /// dotConnect的默认DateTime类型是 TimeStamp,无长度限制的String 是 Clob
        /// </summary>
        /// <param name="modelBuilder"></param>
        public static void AdjustOracleDefaultAction(this ModelBuilder modelBuilder) {
            foreach (var item in modelBuilder.Model
                .GetEntityTypes()
                .SelectMany(t => t.GetProperties())
                .Where(p => p.ClrType == typeof(string) || NoneAnnotationDateTime(p))
                .Select(p => new {
                    p.ClrType,
                    p.Name,
                    Pb = modelBuilder.Entity(p.DeclaringEntityType.ClrType).Property(p.Name),
                    MaxLength = p.GetMaxLength()
                })) {
                if (item.ClrType == typeof(DateTime?)) {
                    item.Pb.HasColumnType("date");
                } else
                if (item.Name == "Discriminator")
                    item.Pb.HasMaxLength(100);
                // ReSharper disable once PossibleInvalidOperationException
                else if (item.ClrType == typeof(string) && item.MaxLength == null)
                    item.Pb.HasMaxLength(2000);
            }
        }

  这里通过一些实际项目中经验来讲述EntityFrameworkCore的一些特性,后续有进一步的新的内容也会不断加入,从而使文章内容更加丰富。

EntityFrameworkCore中的OnModelCreating

原文:https://www.cnblogs.com/seekdream/p/10641510.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!