红色猎鹰 發表於 2025-5-17 08:21:00

ASP.NET Core EFCore 属性配置与DbContext 详解

<p data-pm-slice="0 0 []"><span><span>本文将深入探讨 ASP.NET Core 中 EFCore 的实体属性配置方法及&nbsp;<code><span><span>DbContext</span></span></code><span><span>&nbsp;的核心用法,帮助开发者高效管理数据模型与数据库交互。</span></span></span></span></p>
<hr>
<h4><strong><span><span>一、属性配置</span></span></strong></h4>
<p><span><span>实体属性配置是定义模型与数据库映射的核心,EFCore 提供两种方式:<strong><span><span>数据注解</span></span></strong><span><span>和&nbsp;<strong><span><span>Fluent API</span></span></strong><span><span>。</span></span></span></span></span></span></p>
<h5><span><span>1. 数据注解(Data Annotations)</span></span></h5>
<p><span><span>通过特性(Attributes)直接在实体类上声明配置,适合简单场景。</span></span></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> Product{    <br> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 主键    <br>public int Id { get; set; }</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 非空且最大长度100    <br>public string Name { get; set; }</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 外键    <br>public int CategoryId { get; set; }    <br>public Category Category { get; set; }}</span></pre>
</div>
<p><strong><span><span>常用注解:</span></span></strong></p>
<ul class="list-paddingleft-1">
<li>
<p><code><span><span></span></span></code><span><span>:主键</span></span></p>
</li>
<li>
<p><code><span><span></span></span></code><span><span>:非空约束</span></span></p>
</li>
<li>
<p><code><span><span></span></span></code><span><span>:最大长度</span></span></p>
</li>
<li>
<p><code><span><span></span></span></code><span><span>:外键关系</span></span></p>
</li>
<li>
<p><code><span><span></span></span></code><span><span>:自定义表名</span></span></p>
</li>
</ul>
<h5><span><span>2. Fluent API</span></span></h5>
<p><span><span>在&nbsp;<code><span><span>DbContext</span></span></code><span><span>&nbsp;的&nbsp;<code><span><span>OnModelCreating</span></span></code><span><span>&nbsp;方法中配置,提供更灵活的方式。</span></span></span></span></span></span></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, 255, 1)">void</span> OnModelCreating(ModelBuilder modelBuilder){   <br> modelBuilder.Entity&lt;Product&gt;(entity =&gt;    {       <br> entity.HasKey(p =&gt; p.Id); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 主键   <br>   entity.Property(p =&gt; p.Name)         <br>   .IsRequired()          <br>    .HasMaxLength(100);</span>
      entity.HasOne(p =&gt; p.Category) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 一对一/多关系      <br>      .WithMany(c =&gt; c.Products)          <br>    .HasForeignKey(p =&gt; p.CategoryId); <br>   });}</span></pre>
</div>
<p><strong><span><span>常用配置方法:</span></span></strong></p>
<ul class="list-paddingleft-1">
<li>
<p><code><span><span>HasKey()</span></span></code><span><span>:定义主键</span></span></p>
</li>
<li>
<p><code><span><span>Property().IsRequired()</span></span></code><span><span>:非空约束</span></span></p>
</li>
<li>
<p><code><span><span>HasIndex()</span></span></code><span><span>:创建索引</span></span></p>
</li>
<li>
<p><code><span><span>HasOne().WithMany()</span></span></code><span><span>:配置导航关系</span></span></p>
</li>
</ul>
<p><strong><span><span>优势:</span></span></strong></p>
<ul class="list-paddingleft-1">
<li>
<p><span><span>集中管理配置,避免污染实体类。</span></span></p>
</li>
<li>
<p><span><span>支持复杂配置(如复合主键、继承映射)。</span></span></p>
</li>
</ul>
<hr>
<h4><strong><span><span>二、DbContext 详解</span></span></strong></h4>
<p><code><span><span>DbContext</span></span></code><span><span>&nbsp;是 EFCore 的核心,负责数据库连接、查询、事务管理等。</span></span></p>
<h5><span><span>1.<span>&nbsp;定义 DbContext</span></span></span></h5>
<p><span><span>派生类需继承&nbsp;<code><span><span>DbContext</span></span></code><span><span>,并暴露&nbsp;<code><span><span>DbSet&lt;T&gt;</span></span></code><span><span>&nbsp;属性。</span></span></span></span></span></span></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> AppDbContext : DbContext{    <br><br><span style="color: rgba(0, 0, 255, 1)">public</span> DbSet&lt;Product&gt; Products { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span>; }    <br><span style="color: rgba(0, 0, 255, 1)">public</span> DbSet&lt;Category&gt; Categories { <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)">protected</span> <span style="color: rgba(0, 0, 255, 1)">override</span> <span style="color: rgba(0, 0, 255, 1)">void</span> OnConfiguring(DbContextOptionsBuilder options)      <br>=&gt; options.UseSqlServer(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Your_Connection_String</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> OnModelCreating(ModelBuilder modelBuilder)   <br>  {      <br><span style="color: rgba(0, 128, 0, 1)">  //</span><span style="color: rgba(0, 128, 0, 1)"> Fluent API 配置    <br>  }<br>}</span></pre>
</div>
<h5><span><span>2.&nbsp;<span>生命周期与依赖注入</span></span></span></h5>
<p><span><span>在 ASP.NET Core 中,通过依赖注入管理上下文生命周期:</span></span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Startup.cs<br>services.AddDbContext&lt;AppDbContext&gt;(options =&gt;    <br>options.UseSqlServer(Configuration.GetConnectionString("Default")));</span></pre>
</div>
<ul class="list-paddingleft-1">
<li>
<p><strong><span><span>作用域(Scoped)</span></span></strong><span><span>:默认选项,每个请求一个实例,确保线程安全。</span></span></p>
</li>
<li>
<p><span><span>避免长时间持有&nbsp;<code><span><span>DbContext</span></span></code><span><span>,以防内存泄漏。</span></span></span></span></p>
</li>
</ul>
<h5><span><span>3. 数据操作</span></span></h5>
<ul class="list-paddingleft-1">
<li>
<p><strong><span><span>查询</span></span></strong><span><span>:</span></span></p>
</li>
</ul>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> products = <span style="color: rgba(0, 0, 255, 1)">await</span> _context.Products.Where(p =&gt; p.Price &gt; <span style="color: rgba(128, 0, 128, 1)">50</span>).ToListAsync();</pre>
</div>
<ul class="list-paddingleft-1">
<li>
<p><strong><span><span>保存变更</span></span></strong><span><span>:</span></span></p>
</li>
</ul>
<div class="cnblogs_code">
<pre>_context.Products.Add(newProduct);<br><span style="color: rgba(0, 0, 255, 1)">await</span> _context.SaveChangesAsync();</pre>
</div>
<p><strong><span><span>关键方法:</span></span></strong></p>
<ul class="list-paddingleft-1">
<li>
<p><code><span><span>Add()</span></span></code><span><span>,&nbsp;<code><span><span>Remove()</span></span></code><span><span>:跟踪实体状态</span></span></span></span></p>
</li>
<li>
<p><code><span><span>SaveChangesAsync()</span></span></code><span><span>:提交事务</span></span></p>
</li>
</ul>
<h5><span><span>4. 性能优化</span></span></h5>
<ul class="list-paddingleft-1">
<li>
<p><strong><span><span>AsNoTracking()</span></span></strong><span><span>:禁用变更跟踪,提升查询速度。</span></span></p>
</li>
<li>
<p><strong><span><span>DbContext 池</span></span></strong><span><span>:复用上下文实例,减少开销。</span></span></p>
</li>
</ul>
<div class="cnblogs_code">
<pre>services.AddDbContextPool&lt;AppDbContext&gt;(...);</pre>
</div>
<hr>
<h4><strong><span><span>三、高级配置</span></span></strong></h4>
<h5><span><span>1. 多对多关系</span></span></h5>
<p><span><span>使用 Fluent API 配置中间表:</span></span></p>
<div class="cnblogs_code">
<pre>modelBuilder.Entity&lt;Post&gt;()    <br>.HasMany(p =&gt; p.Tags)    <br>.WithMany(t =&gt; t.Posts)    <br>.UsingEntity(j =&gt; j.ToTable(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">PostTags</span><span style="color: rgba(128, 0, 0, 1)">"</span>));</pre>
</div>
<h5><span><span>2. 继承映射</span></span></h5>
<p><span><span>TPH(Table-Per-Hierarchy)模式:</span></span></p>
<div class="cnblogs_code">
<pre>modelBuilder.Entity&lt;Blog&gt;()    <br>.HasDiscriminator&lt;<span style="color: rgba(0, 0, 255, 1)">string</span>&gt;(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">BlogType</span><span style="color: rgba(128, 0, 0, 1)">"</span>)    <br>.HasValue&lt;Blog&gt;(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Standard</span><span style="color: rgba(128, 0, 0, 1)">"</span>)    <br>.HasValue&lt;RssBlog&gt;(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">RSS</span><span style="color: rgba(128, 0, 0, 1)">"</span>);</pre>
</div>
<h5><span><span>3. 全局过滤器</span></span></h5>
<p><span><span>自动应用查询条件(如软删除):</span></span></p>
<div class="cnblogs_code">
<pre>modelBuilder.Entity&lt;Post&gt;().HasQueryFilter(p =&gt; !p.IsDeleted);</pre>
</div>
<hr>
<h4><strong><span><span>四、最佳实践与常见问题</span></span></strong></h4>
<ol class="list-paddingleft-1">
<li>
<p><strong><span><span>选择数据注解还是 Fluent API?</span></span></strong></p>
</li>
<ul class="list-paddingleft-1">
<li>
<p><span><span>简单配置用数据注解,复杂需求用 Fluent API。</span></span></p>
</li>
</ul>
<li>
<p><strong><span><span>DbContext 线程安全</span></span></strong></p>
</li>
<ul class="list-paddingleft-1">
<li>
<p><span><span>确保每个请求使用独立实例,避免并发问题。</span></span></p>
</li>
</ul>
<li>
<p><strong><span><span>迁移(Migrations)</span></span></strong></p>
</li>
<ul class="list-paddingleft-1">
<li>
<p><span><span>通过&nbsp;<code><span><span>dotnet ef migrations add</span></span></code><span><span>&nbsp;生成数据库架构变更。</span></span></span></span></p>
</li>
</ul>
<li>
<p><strong><span><span>性能陷阱</span></span></strong></p>
</li>
<ul class="list-paddingleft-1">
<li>
<p><span><span>避免在循环中频繁调用&nbsp;<code><span><span>SaveChanges()</span></span></code><span><span>。</span></span></span></span></p>
</li>
<li>
<p><span><span>使用&nbsp;<code><span><span>Include()</span></span></code><span><span>&nbsp;预加载关联数据,减少 N+1 查询。</span></span></span></span></p>
</li>
</ul>
</ol><hr>
<h4><strong><span><span>结语</span></span></strong></h4>
<p><span><span>掌握 EFCore 的属性配置与&nbsp;<code><span><span>DbContext</span></span></code><span><span>&nbsp;管理,能够显著提升数据层开发效率。合理选择配置方式,结合依赖注入和性能优化技巧,可构建高效稳健的 ASP.NET Core 应用。</span></span></span></span></p><br><br>
来源:https://www.cnblogs.com/shenchuanchao/p/18879792
頁: [1]
查看完整版本: ASP.NET Core EFCore 属性配置与DbContext 详解