初始化及配置


  EntityContext 在使用之前,要确保能够正确地连接到目标数据库,如果你未指定数据库连接串,那么 EntityContext 就无法正常工作。EntityContext 的配置有以下几种。


1、默认配置

  在提供数据库实例配置的情况下,你可以什么都不用考虑,只需 new EntityContext() 来使用。如数据库实例配置如下:

  • .Net Framework 下的 app.config 或 web.config 文件
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <sectionGroup name="fireasy">
      <section name="dataInstances" type="Fireasy.Data.Configuration.InstanceConfigurationSectionHandler, Fireasy.Data" />
    </sectionGroup>
  </configSections>
  <fireasy>
    <dataInstances default="sqlite">
      <instance name="mysql" providerType="MySql" connectionString="Data Source=localhost;database=Northwind;User Id=root;password=faib;pooling=true;charset=utf8"></instance>
      <instance name="mssql" providerType="MsSql" connectionString="data source=(local);user id=sa;password=123;initial catalog=fireasy-db"></instance>
      <instance name="sqlite" providerType="SQLite" connectionString="Data source=|datadirectory|documents/db/northwind.db3;Pooling=True"></instance>
    </dataInstances>
  </fireasy>
</configuration>
  • .Net Core 下的 appsettings.json 文件
{
   "fireasy": {
    "dataInstances": {
      "default": "sqlite",
      "settings": {
        "mysql": {
          "providerType": "MySql",
          "connectionString": "Data Source=localhost;database=northwind;User Id=root;password=faib;pooling=true;charset=utf8"
        },
        "mssql": {
          "providerType": "MsSql",
          "connectionString": "data source=(local);user id=sa;password=123;initial catalog=test;"
        },
        "sqlite": {
          "providerType": "SQLite",
          "connectionString": "Data source=|datadirectory|documents/db/northwind.db3"
        }
      }
    }
  }
}

  那么 Fireasy 将使用 default 的默认数据库实例来创建 EntityContext 对象。


2、重写构造函数

  如果你需要定义两个不同的 EntityContext,而每一个都绑定不同的数据库,此时就需要重写构造函数来指定使用哪一个数据库实例了。下面的示例中,DbContext1 使用 mssql 实例,DbContext2 使用 sqlite 实例。

public class DbContext1 : EntityContext
{
    public DbContext1()
      : base ("mssql")
    {
    }
}

public class DbContext2 : EntityContext
{
    public DbContext2()
      : base ("sqlite")
    {
    }
}

3、重写 OnConfiguring 方法

  没有使用实例配置的情况下,你可以重写 OnConfiguring 方法来指定数据库提供者(可参考 数据库提供者)和数据库连接串。

public class DbContext : EntityContext
{
    protected override void OnConfiguring(EntityContextOptionsBuilder builder)
    {
      builder.Options.Provider = SQLiteProvider.Instance; //指定数据库提供者
      builder.Options.ConnectionString = "Data source=|datadirectory|documents/db/northwind.db3";
    }
}

4、使用 Use* 扩展方法

  你还可以使用 EntityContextOptionsBuilder 的扩展方法 Use* 来指定数据库连接串。它提供了类似的方法有:

  • UseSqlServer: 使用 SqlServer 数据库
  • UseMySql: 使用 MySql 数据库
  • UseSQLite: 使用 SQLite 数据库
  • UseOracle: 使用 Oracle 数据库
  • UseFirebird: 使用 Firebird 数据库
  • UsePostgreSql: 使用 PostgreSql 数据库
public class DbContext : EntityContext
{
    protected override void OnConfiguring(EntityContextOptionsBuilder builder)
    {
        builder.UseSQLite("Data source=|datadirectory|documents/db/northwind.db3");
    }
}

  另外,在 .Net Core 程序的配置中,也可以在 Startup.ConfigureServices 方法里使用 Use*。

namespace demo
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddFireasy(Configuration);
            services.AddEntityContext<DbContext>(builder =>
                {
                    builder.UseSQLite("Data source=|datadirectory|documents/db/northwind.db3");
                });
        }
    }
}

5、配置 EntityContextOptions

  重写 EntityContext 构造函数,或重写 OnConfiguring 方法时,可以对 EntityContextOptions 进行设置。   EntityContextOptions 类的各属性含义如下:

  • ConfigName:指定数据库配置实例的名称,如上面配置中的 mssql、sqlite、mysql 等等,如果不指定则使用默认实例。
  • Provider:指定数据库提供者。
  • ConnectionString:指定数据库连接串。
  • NotifyEvents:指定是否开启持久化事件订阅。默认是关闭的。
  • ValidateEntity:指定是否验证实体及属性。默认是开启的。
  • AllowDefaultValue:指定是否分配默认值,当开启时,即使你没有对属性赋值,也会使用 PropertyMappingAttribute 指定的默认值为属性赋值。默认是开启的。
  • IsolationLevel:指定数据库事务的默认隔离级别,默认为 IsolationLevel.ReadUncommitted
  • CacheParsing:指定是否开启 lambda 表达式的解析缓存。
  • CacheParsingTimes:指定解析缓存的有效时间。
  • CacheExecution:指定是否开启查询结果集的缓存。
  • CacheExecutionTimes:指定数据缓存的有效时间。
  • LoadBehavior:指定关联属性的加载行为,默认是延迟加载。
public class DbContext : EntityContext
{
    public DbContext()
      : base (new EntityContextOptions { ConfigName = "mysql", NotifyEvents = true })
    {
    }
        
    protected override void OnConfiguring(EntityContextOptionsBuilder builder)
    {
        builder.Options.NotifyEvents = false;  //最终以这里的设置为准
    }
}

  EntityContextOptions 类的 Initializers 属性允许你添加初始化处理。它是实现 IEntityContextPreInitializer 接口的类型。Initializers 中默认添加了 RecompileAssemblyPreInitializer 类,它是负责编译所有实体代理类的处理器。除此之外,UseCodeFirst 和 UseOracleTrigger 方法也是应用了 IEntityContextPreInitializer 接口。


6、使用 CodeFirst 模式

  重写 OnConfiguring 方法时,可以使用扩展方法 UseCodeFirst 来开启 CodeFirst 模式。它会使用 ITableGenerateProvider 扩展服务来检测实体的变动并生成相应的 DDL 执行到数据库中。开启 CodeFirst 后,应用的性能会有所下降。如下所示:

public class DbContext : EntityContext
{
    protected override void OnConfiguring(EntityContextOptionsBuilder builder)
    {
        builder.UseCodeFirst();
    }
}

7、Oracle 使用触发器赋值主键

  Oracle 没有自增特性,只能使用序列值,默认下主键值是通 标识生成服务 得到序列值的,这就意味着新增操作被放弃(比如数据未通过验证),序列值仍然被消耗,这就导致了数据的不连贯。重写 OnConfiguring 方法时,可以使用扩展方法 UseOracleTrigger 来创建触发器以便实时得到序列值。如果 UseOracleTrigger 泛型方法指定具体的实体类时,则仅此实体类会应用这种机制,缺省情况下所有实体类都会被应用此机制。如下所示:

public class DbContext : EntityContext
{
    protected override void OnConfiguring(EntityContextOptionsBuilder builder)
    {
        //builder.UseOracleTrigger(); //所有实体类都应用此机制
        builder.UseOracleTrigger<Orders>(); //仅 Orders 会被应用
    }
}

8、更改 IProvider 插件服务

  在某些情况下,你可能需要更改 插件服务,此时可使用 UseServiceProvider 方法。比如,使用雪花算法来生成主键值,并使用自定义的语法插件,可参考以下所示代码:

public class MySnowflakeGenerator : SnowflakeGenerator
{
    public MySnowflakeGenerator(IServiceProvider serviceProvider)
    {
        var configuration = serviceProvider.GetService<IConfiguration>();
        //WorkerId放在配置文件 appsettings.json 中
        WorkerId = Convert.ToInt32(configuration.GetSection("Snowflake:WorkerId").Value);
    }
}

public class MyMsSqlSyntax : MsSqlSyntax
{
}

public class DbContext : EntityContext
{
    protected override void OnConfiguring(EntityContextOptionsBuilder builder)
    {
        builder.UseProviderService(new MySnowflakeGenerator(builder.Options.ServiceProvider));
        builder.UseProviderService<MyMsSqlSyntax>();
    }
}