悦已 發表於 2025-9-24 18:05:00

【EF Core】框架底层的数据库连接管理

<p>在开始水文章前,老周补充说明一下,在前一篇水文中,老周扯了跟 Owned 关系相关的一些话题,这里补充一句:Owned 关系是不存在“多对多”的,如果 A 实体 Own B 实体,那么,A 对 B 是完全占有,B只属于A,数据不共享,这样就不存在“多”的一端;但A可以同时占用B、C实体,所以一占多是存在的。说得简单一点,就是 B 都被 A 独占了,其他人还来凑啥热闹?</p>
<p>好了,正片开始!外面台风呼啸,雨声沥沥,很适合探讨一些轻松的话题。于是,老周就说一下 EF Core 底层对数据库连接的管控吧。其实,各位如果项目中常用 EF Core,就会发现,大多数时候我们根本不用去考虑连接数据库的事,引用数据库对应的包,添加 Provider(指 UseSql、UseSqlite 等方法的调用),传递一个连接字符串就完事了。</p>
<p>这是因为 EF Core 已经把数据库连接相关操作封装了。实际上它的底层还是会用到 ADO.NET 相关的 API。嗯,就是大伙都很熟悉的三件套:DbConnection、DbCommand、DbDataReader。当然,这里列出的是通过的类,还有 DbBatch、DbDataAdapter 等类,只是不完全通用,有些数据库是不提供的。这些以 Db 开头的类均位于 System.Data.Common 空间,属于公共基类,不同的数据库必须提供自身的实现类。如:</p>
<p><strong><span style="color: rgba(0, 0, 255, 1)">1、SQL Server:</span></strong>SqlConnection、SqlCommand、SqlDataReader;</p>
<p><strong><span style="color: rgba(0, 0, 255, 1)">2、SQLite:</span></strong>SqliteConnection、SqliteCommand、SqliteDataReader;</p>
<p><strong><span style="color: rgba(0, 0, 255, 1)">3、PostgreSQL:</span></strong>NpgsqlConnection、NpgsqlCommand、NpgsqlDataReader;</p>
<p>……</p>
<p>其中,SQL Server 和 PostgreSQL 是有 DataAdapter 的,分别是 <span style="color: rgba(0, 0, 255, 1)">SqlDataAdapter</span> 和&nbsp;<span style="color: rgba(0, 0, 255, 1)">NpgsqlDataAdapter</span>。SQLite 没有提供。</p>
<p>这样就保证了尽管面向不同的数据库,但 API 的调用过程差不多:</p>
<p><span style="color: rgba(0, 0, 255, 1)">A、实例化 XXXConnection;</span></p>
<p><span style="color: rgba(0, 0, 255, 1)">B、创建 XXXCommand 实例,设置 SQL 语句;</span></p>
<p><span style="color: rgba(0, 0, 255, 1)">C、XXXCommand 实例调用 ExecuteXXX 执行 SQL,可能不需要返回结果,也可能需要 XXXDataReader 来读取结果;</span></p>
<p><span style="color: rgba(0, 0, 255, 1)">D、关闭 XXXConnection 对象。</span></p>
<p>由于各种数据库相关的连接对象都是 DbConnection 的子类,于是,在连接管理上,只要统使用 DbConnection 类型就能把连接管理抽象出来,统一描述。为了实现这个“宏大目标”,EF Core 在面向关系数据库专用包(xxxx.Relational.dll)中提供了&nbsp;<strong><span style="color: rgba(0, 0, 255, 1)">IRelationalConnection</span> </strong>接口。这个接口完成了以下规范:</p>
<p><strong><span style="color: rgba(0, 0, 255, 1)">1、ConnectionString 属性:</span></strong>通过它,你可以设置 / 获取连接字符串;<br></p>
<p><strong><span style="color: rgba(0, 0, 255, 1)">2、DbConnection 属性:</span></strong>这个很重要,有了此属性,就可以设置 / 获取连接对象了,定义的类型正是公共基类&nbsp;DbConnection;</p>
<p><span style="color: rgba(0, 0, 255, 1)"><strong>3、Open / OpenAsync 方法:</strong></span>打开连接;</p>
<p><strong><span style="color: rgba(0, 0, 255, 1)">4、Close / CloseAsync 方法:</span></strong>关闭连接;</p>
<p><strong><span style="color: rgba(0, 0, 255, 1)">5、RentCommand 方法:</span></strong>调用它,它会自动帮你创建/重用一个命令实例,用&nbsp;IRelationalCommand 接口封装了。这个接口稍后再介绍;</p>
<p><strong><span style="color: rgba(0, 0, 255, 1)">6、ReturnCommand 方法:</span></strong>命令对象使用完后,可以调用这个方法,把实例仍回去,以便将来可以重复/或全新使用。框架帮你管理其内存,不用你操心。</p>
<p>有小伙伴会疑惑:咦,我在 EFCore 源代码中搜索 SqlCommand、SqliteCommand 等关键字,居然找不到它在哪里使用命令。你不要忘了,DbConnection 类有个叫 CreateCommand 的方法,所有派生类都实现这个方法。SqlConnection 类会让它返回 SqlCommand 实例,SqliteConnection 类会让它返回 SqliteCommand 实例。但由于 CreateCommand 方法定义的返回类型是 DbCommand 类,因此它有通用性。EF Core 中就是调用了 CreateCommand 方法来获得命令实例的。这就不得不提前文中出现的一个接口了——&nbsp;IRelationalCommand。它统一了一些方法:</p>
<p><strong><span style="color: rgba(0, 0, 255, 1)">1、ExecuteNonQuery / ExecuteNonQueryAsync 方法:</span></strong>执行命令,通常不返回查询结果,如 INSERT、DELETE 等;</p>
<p><span style="color: rgba(0, 0, 255, 1)"><strong>2、ExecuteReader /&nbsp;ExecuteReaderAsync 方法:</strong></span>执行后会有查询结果,但 XXXDataReader 类被&nbsp;RelationalDataReader 类封装了;</p>
<p><strong><span style="color: rgba(0, 0, 255, 1)">3、ExecuteScalar /&nbsp;ExecuteScalarAsync 方法:</span></strong>返回单个值。</p>
<p>IRelationalCommand 接口的实现类是&nbsp;RelationalCommand。它有个&nbsp;CreateDbCommand 公共方法。</p>
<div class="cnblogs_code">
<pre>    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">virtual</span><span style="color: rgba(0, 0, 0, 1)"> DbCommand CreateDbCommand(
      RelationalCommandParameterObject parameterObject,
      Guid commandId,
      DbCommandMethod commandMethod)
    {
      </span><span style="color: rgba(0, 0, 255, 1)">var</span> (connection, context, logger) =<span style="color: rgba(0, 0, 0, 1)"> (parameterObject.Connection, parameterObject.Context, parameterObject.Logger);
      </span><span style="color: rgba(0, 0, 255, 1)">var</span> connectionId =<span style="color: rgba(0, 0, 0, 1)"> connection.ConnectionId;

      </span><span style="color: rgba(0, 0, 255, 1)">var</span> startTime =<span style="color: rgba(0, 0, 0, 1)"> DateTimeOffset.UtcNow;

      DbCommand command;

      </span><span style="color: rgba(0, 0, 255, 1)">var</span> stopwatch =<span style="color: rgba(0, 0, 0, 1)"> SharedStopwatch.StartNew();

      </span><span style="color: rgba(0, 0, 255, 1)">var</span> logCommandCreate = logger?.ShouldLogCommandCreate(startTime) == <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
      </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (logCommandCreate)
      {
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> interceptionResult = logger!<span style="color: rgba(0, 0, 0, 1)">.CommandCreating(
                connection, commandMethod, context, commandId, connectionId, startTime,
                parameterObject.CommandSource);

            command </span>=<span style="color: rgba(0, 0, 0, 1)"> interceptionResult.HasResult
                </span>?<span style="color: rgba(0, 0, 0, 1)"> interceptionResult.Result
                : <span style="background-color: rgba(255, 255, 0, 1)"><strong>connection.DbConnection.CreateCommand()</strong></span>;

            command </span>=<span style="color: rgba(0, 0, 0, 1)"> logger.CommandCreated(
                connection,
                command,
                commandMethod,
                context,
                commandId,
                connectionId,
                startTime,
                stopwatch.Elapsed,
                parameterObject.CommandSource);
      }
      </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
      {
            <strong><span style="background-color: rgba(255, 255, 0, 1)">command </span></strong></span><strong><span style="background-color: rgba(255, 255, 0, 1)">=</span></strong><span style="color: rgba(0, 0, 0, 1)"><strong><span style="background-color: rgba(255, 255, 0, 1)"> connection.DbConnection.CreateCommand()</span></strong>;
      }

      <span style="background-color: rgba(255, 255, 0, 1)">command.CommandText </span></span><span style="background-color: rgba(255, 255, 0, 1)">=<span style="color: rgba(0, 0, 0, 1)"> CommandText;

</span></span>      <span style="color: rgba(0, 0, 255, 1)">if</span> (connection.CurrentTransaction != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">)
      {
            command.Transaction </span>=<span style="color: rgba(0, 0, 0, 1)"> connection.CurrentTransaction.GetDbTransaction();
      }

      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (connection.CommandTimeout != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">)
      {
            command.CommandTimeout </span>= (<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">)connection.CommandTimeout;
      }

      </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> i = <span style="color: rgba(128, 0, 128, 1)">0</span>; i &lt; Parameters.Count; i++<span style="color: rgba(0, 0, 0, 1)">)
      {
            Parameters.AddDbParameter(command, parameterObject.ParameterValues);
      }

      </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (logCommandCreate)
      {
            command </span>= logger!<span style="color: rgba(0, 0, 0, 1)">.CommandInitialized(
                connection,
                command,
                commandMethod,
                context,
                commandId,
                connectionId,
                startTime,
                stopwatch.Elapsed,
                parameterObject.CommandSource);
      }

      </span><span style="background-color: rgba(255, 255, 0, 1)"><strong><span style="color: rgba(0, 0, 255, 1)">return</span></strong></span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)"><strong> command</strong></span>;
    }</span></pre>
</div>
<p>&nbsp;</p>
<p>好了,现在基本的原理通了,咱们回到&nbsp;IRelationalConnection 接口,它有一个抽象类实现:RelationalConnection。这个类中定义了一个抽象方法叫&nbsp;CreateDbConnection,各种数据库在匹配 API 时会重写此方法。比如:</p>
<p>A、SQLite 数据库提供者,从 RelationalConnection 派生出&nbsp;SqliteRelationalConnection 类,重写&nbsp;CreateDbConnection 方法。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">override</span><span style="color: rgba(0, 0, 0, 1)"> DbConnection CreateDbConnection()
{
    </span><span style="color: rgba(0, 0, 255, 1)">var</span> connection = <span style="color: rgba(0, 0, 255, 1); background-color: rgba(255, 255, 0, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)"> SqliteConnection(GetValidatedConnectionString())</span>;
    InitializeDbConnection(connection);

    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> connection;
}</span></pre>
</div>
<p>B、SQL Server 数据提供者:从&nbsp;RelationalConnection 派生出&nbsp;SqlServerConnection 类,重写&nbsp;CreateDbConnection 方法。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">override</span><span style="color: rgba(0, 0, 0, 1)"> DbConnection CreateDbConnection()
    </span>=&gt; <span style="background-color: rgba(255, 255, 0, 1)"><span style="color: rgba(0, 0, 255, 1)">new</span> SqlConnection(GetValidatedConnectionString())</span>;</pre>
</div>
<p>C、PostgreSQL 数据库提供者:从&nbsp;RelationalConnection 派生出&nbsp;NpgsqlRelationalConnection 类,重写&nbsp;CreateDbConnection 方法。</p>
<div class="cnblogs_code">
<pre>    <span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">override</span><span style="color: rgba(0, 0, 0, 1)"> DbConnection CreateDbConnection()
    {
      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (DataSource <span style="color: rgba(0, 0, 255, 1)">is</span> not <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">)
      {
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)"> DataSource.CreateConnection();</span>
      }

      </span><span style="color: rgba(0, 0, 255, 1)">var</span> conn = <span style="background-color: rgba(255, 255, 0, 1)"><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> NpgsqlConnection(ConnectionString);

</span></span>      <span style="color: rgba(0, 0, 255, 1)">if</span> (_provideClientCertificatesCallback <span style="color: rgba(0, 0, 255, 1)">is</span> not <span style="color: rgba(0, 0, 255, 1)">null</span> || _remoteCertificateValidationCallback <span style="color: rgba(0, 0, 255, 1)">is</span> not <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">)
      {
            conn.SslClientAuthenticationOptionsCallback </span>= o =&gt;<span style="color: rgba(0, 0, 0, 1)">
            {
                </span><span style="color: rgba(0, 0, 255, 1)">if</span> (_provideClientCertificatesCallback <span style="color: rgba(0, 0, 255, 1)">is</span> not <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">)
                {
                  o.ClientCertificates </span>??= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)">();
                  _provideClientCertificatesCallback(o.ClientCertificates);
                }

                o.RemoteCertificateValidationCallback </span>=<span style="color: rgba(0, 0, 0, 1)"> _remoteCertificateValidationCallback;
            };
      }

      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (_providePasswordCallback <span style="color: rgba(0, 0, 255, 1)">is</span> not <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">)
      {
</span><span style="color: rgba(0, 0, 255, 1)">#pragma</span> warning disable 618 <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ProvidePasswordCallback is obsolete</span><span style="color: rgba(0, 0, 0, 1)">
            conn.ProvidePasswordCallback </span>=<span style="color: rgba(0, 0, 0, 1)"> _providePasswordCallback;
</span><span style="color: rgba(0, 0, 255, 1)">#pragma</span> warning restore 618<span style="color: rgba(0, 0, 0, 1)">
      }

      </span><span style="color: rgba(0, 0, 255, 1); background-color: rgba(255, 255, 0, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)"> conn;</span>
    }</span></pre>
</div>
<p>&nbsp;</p>
<p>每个数据库提供者都会把实现 IRelationalConnection 接口的类注册到服务容器中,也就是说,咱们在应用代码中是可以访问此接口的功能的。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 构建连接字符串</span>
SqliteConnectionStringBuilder csbuilder = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)">();
csbuilder.DataSource </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">test.db</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
csbuilder.Password </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">huhuhahe</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 构建选项</span>
DbContextOptions&lt;DbContext&gt; options = <span style="color: rgba(0, 0, 255, 1)">new</span> DbContextOptionsBuilder&lt;DbContext&gt;<span style="color: rgba(0, 0, 0, 1)">()
    .UseSqlite(csbuilder.ConnectionString)
    .Options;

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 此处只用来测试 IRelationalConnection 服务的访问、
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 所以无实体类无 DbContext 的派生类</span>
<span style="color: rgba(0, 0, 255, 1)">using</span> DbContext context = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)">(options);

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取服务</span>
IRelationalConnection conn = <span style="background-color: rgba(255, 255, 0, 1)"><strong>context.GetService&lt;IRelationalConnection&gt;</strong></span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)"><strong>()</strong></span>;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 打印连接字符串</span>
Console.WriteLine($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">连接字符串:{<strong><span style="background-color: rgba(255, 255, 0, 1)">conn.ConnectionString</span></strong>}</span><span style="color: rgba(128, 0, 0, 1)">"</span>);</pre>
</div>
<p>代码运行后,输出结果如下:</p>
<div class="cnblogs_code">
<pre>连接字符串:Data Source=test.db;Password=huhuhahe</pre>
</div>
<p>&nbsp;</p>
<p>------------------------------------------------------------------------------------------------------------------------------------------------------------</p>
<p>上面的示例其实没啥鸟用,接下来老周讲个比较有实用性的。下面咱们看看共享 DbConnection。</p>
<p>实体和 Context 如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Dog
{
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> Guid DogId { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Name { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span>; } = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Who?</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> Age { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span>? Category { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> MyDbContext : DbContext
{
    </span><span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">override</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> OnModelCreating(ModelBuilder modelBuilder)
    {
      EntityTypeBuilder</span>&lt;Dog&gt; tb = modelBuilder.Entity&lt;Dog&gt;<span style="color: rgba(0, 0, 0, 1)">();
      tb.HasKey(d </span>=&gt; d.DogId).HasName(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">PK_Dog</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
      tb.ToTable(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">tb_dogs</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
      tb.Property(x </span>=&gt; x.Name).HasMaxLength(<span style="color: rgba(128, 0, 128, 1)">20</span><span style="color: rgba(0, 0, 0, 1)">).IsRequired();
      tb.Property(a </span>=&gt; a.Category).HasDefaultValue(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">未确认</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
    }

    </span><span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">override</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
      <strong><span style="background-color: rgba(255, 255, 0, 1)">optionsBuilder.UseSqlite(_connection)</span></strong>;
    }

    <span style="background-color: rgba(255, 255, 0, 1)">DbConnection _connection</span>;
    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> MyDbContext(<span style="background-color: rgba(255, 255, 0, 1)"><strong>DbConnection c</strong></span>)
    {
      <span style="background-color: rgba(255, 255, 0, 1)">_connection </span></span><span style="background-color: rgba(255, 255, 0, 1)">=</span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)"> c</span>;
    }

    </span><span style="color: rgba(0, 0, 255, 1)">public</span> DbSet&lt;Dog&gt; DogSet { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
}</span></pre>
</div>
<p>注意这个 MyDbContext 类,它的构造函数可以传递 DbConnection 对象,然后在重写的 OnConfiguring 方法中调用 UseSqlite 扩展方法直接引用外部的 DbConnection 对象。这样就实现了连接对象的共享。接着看代码:</p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> Main(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">[] args)
{
   <span style="background-color: rgba(255, 255, 0, 1)"><strong>SqliteConnection myconn </strong></span></span><span style="background-color: rgba(255, 255, 0, 1)"><strong>= <span style="color: rgba(0, 0, 255, 1)">new</span>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">data source=mme.db</span><span style="color: rgba(128, 0, 0, 1)">"</span></strong></span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)"><strong>)</strong></span>;
   </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 初始化数据库</span>
   <span style="color: rgba(0, 0, 255, 1)">using</span> (<span style="background-color: rgba(255, 255, 0, 1)">MyDbContext ctx = <span style="color: rgba(0, 0, 255, 1)">new</span></span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)">(myconn)</span>)
   {
         ctx.Database.EnsureDeleted();
         ctx.Database.EnsureCreated();
   }
   </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 插入数据</span>
   <span style="color: rgba(0, 0, 255, 1)">using</span> (<span style="background-color: rgba(255, 255, 0, 1)"><span style="color: rgba(0, 0, 255, 1)">var</span> ctx = <span style="color: rgba(0, 0, 255, 1)">new</span></span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)"> MyDbContext(myconn)</span>)
   {
         ctx.DogSet.Add(</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)">()
         {
             Name </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">小菜</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
             Age </span>= <span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">,
             Category </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">吉娃娃</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
         });
         ctx.DogSet.Add(</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)">()
         {
             Name </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Jimy</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
             Age </span>= <span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">,
             Category </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">贵宾犬</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
         });
         ctx.SaveChanges();
   }
   </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 查询数据</span>
   <span style="color: rgba(0, 0, 255, 1)">using</span> (<span style="background-color: rgba(255, 255, 0, 1)">MyDbContext c = <span style="color: rgba(0, 0, 255, 1)">new</span></span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)"> MyDbContext(myconn)</span>)
   {
         </span><span style="color: rgba(0, 0, 255, 1)">foreach</span> (Dog d <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> c.DogSet)
         {
             Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{d.Name} - {d.Category}, {d.Age}岁</span><span style="color: rgba(128, 0, 0, 1)">
"</span><span style="color: rgba(128, 0, 0, 1)">);</span>
<span style="color: rgba(0, 0, 0, 1)">         }
   }
}</span></pre>
</div>
<p>先实例化连接对象,然后依次传递三个 MyDbContext 实例使用。</p>
<p>好了,今天咱们就水到这里吧。</p><br><br>
来源:https://www.cnblogs.com/tcjiaan/p/19108838
頁: [1]
查看完整版本: 【EF Core】框架底层的数据库连接管理