【EF Core】带主键实体与无主键实体
<p>上一次老周已介绍了 EF Core 框架自动发现实体和实体成员的原理。涉及到对源码的分析,可能大伙伴们都看得气压升高了。故这一次老周不带各位去分析源码了,咱们聊一聊熟悉又陌生的关键词——主键。说它熟悉,是因为只要咱们创建数据表,99%会用到;说它陌生,是指在 EF Core 中与主键相关的细节。</p><p>Primary Key,翻译为“主键”(这个翻译老周没意见,但 Thread 翻译成“线程”感觉莫名其妙)。按其命名,即是一张表中主要的键,用于表明某行记录在表中是唯一的。有大伙伴会说,那 Unique 约束也可以啊。是的,但还要有一个条件,就是不能为空值,所以,可以说主键是 UNIQUE 和 NOT NULL 的结合。</p>
<p>数据表的主键可以是一列,也可以是多列。</p>
<p>好了,概念说完了,咱们说回 EF。按照预置的约定(老周上一文中介绍),将属性发现为主键的原则有:</p>
<p><span style="color: rgba(0, 0, 128, 1)">1、属性名为 Id;</span></p>
<p><span style="color: rgba(0, 0, 128, 1)">2、属性名为实体类名 + Id,如 ProductId、OrderId 等。</span></p>
<p>最常用的类型是 int,自动增长。也可以用 GUID,GUID 属性的类型可以定义为 Guid,也可以是 string。老周,有例子吗?有,咱们玩几个,咱们使用 Sqlite 数据库来演示。</p>
<p>1、创建一个控制台应用。</p>
<div class="cnblogs_code">
<pre>dotnet <span style="color: rgba(0, 0, 255, 1)">new</span> console -n Demo -o .</pre>
</div>
<p>有伙伴会问:这个用 Copilot 能不能执行?可以,比如这样:</p>
<p><img src="https://img2024.cnblogs.com/blog/367389/202507/367389-20250720120659211-1222786125.png" alt="" width="294" height="182" loading="lazy"></p>
<p>它生成的命令少了 -o . ,你可以手动补上。</p>
<p><img src="https://img2024.cnblogs.com/blog/367389/202507/367389-20250720120754278-817679621.png" alt="" width="335" height="192" loading="lazy"></p>
<p>如果你不想它自动执行命令,那不要点“继续”,复制命令文本后,点“取消”就好。若继续,它会直接执行命令。</p>
<p>尽管可以这样用,但这样做特愚蠢!你直接打个命令都比这个快了。写实体类的时候,如果你不想重复敲 get 和 set,倒可以用它辅助。当然,VS其实也会提示的,你按个 Tab 就会生成了。这个东西虽然好用,但有时候也挺烦的,按个 Tab 就出一堆东西(如果不想禁掉它,可以按 Esc 键取消提示)。如果你真不想用它,可以到设置里面找到【文本编辑器】-【建议】,去掉 Inline Suggest: Enabled 的选项即可。</p>
<p><img src="https://img2024.cnblogs.com/blog/367389/202507/367389-20250720182354866-1601142312.png" alt="" width="375" height="187" loading="lazy"></p>
<p> </p>
<p>2、定义实体类。这次咱们用一个 Pet 类,表示你家的宠物。</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)"> Pet
{
</span><span style="background-color: rgba(255, 255, 0, 1)"><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> id { <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> <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(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> Cate { <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>这个你倒可以用辅助工具写。注意这里老周故意把标识属性改为小写,即 id,而不是 Id。待会咱们看看 EF 能不能识别。</p>
<p>3、为项目添加包。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.Sqlite</span></pre>
</div>
<p>4、写数据上下文类。</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)"> MyDbContext : DbContext
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> MyDbContext(DbContextOptions<MyDbContext> options) : <span style="color: rgba(0, 0, 255, 1)">base</span><span style="color: rgba(0, 0, 0, 1)">(options)
{
}
</span><span style="background-color: rgba(255, 255, 0, 1)"><span style="color: rgba(0, 0, 255, 1)">public</span> DbSet<Pet> Pets { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span></span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)">; }</span>
}</span></pre>
</div>
<p>5、这一次咱们的连接字符串不在 MyDbContext 内部配置,而是外部构建 Options 来配置。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 创建选项类实例</span>
DbContextOptions<MyDbContext> options = <span style="color: rgba(0, 0, 255, 1)">new</span> DbContextOptionsBuilder<MyDbContext><span style="color: rgba(0, 0, 0, 1)">()
.<strong><span style="background-color: rgba(255, 255, 0, 1)">UseSqlite(</span></strong></span><strong><span style="background-color: rgba(255, 255, 0, 1)"><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Data Source=mydb.db</span><span style="color: rgba(128, 0, 0, 1)">"</span></span></strong><span style="color: rgba(0, 0, 0, 1)"><strong><span style="background-color: rgba(255, 255, 0, 1)">)</span></strong>
.Options;
</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> <span style="color: rgba(0, 0, 255, 1)">var</span> dc = <span style="color: rgba(0, 0, 255, 1)">new</span> MyDbContext(options);</pre>
</div>
<p>6、这个例子中,咱们不创建数据库,只是验证一下,全小写的 id 属性是否能被识别为主键。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">
此处我们不创建数据库,只是看看它能不能识别出主键
</span><span style="color: rgba(0, 128, 0, 1)">*/</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)">foreach</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> ent <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> dc.Model.GetEntityTypes())
{
Console.Write($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">表名: {ent.<span style="background-color: rgba(255, 255, 0, 1)">GetTableName()</span>}</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>
<span style="color: rgba(0, 0, 255, 1)">var</span> rmykey =<span style="color: rgba(0, 0, 0, 1)"> ent.<span style="background-color: rgba(255, 255, 0, 1)">FindPrimaryKey</span>();
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (rmykey != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">)
{
Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">,主键: {string.Join(</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)">, rmykey.Properties.Select(p => p.Name))}</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>
<span style="color: rgba(0, 0, 255, 1)">foreach</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> property <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> ent.<span style="background-color: rgba(255, 255, 0, 1)">GetProperties</span>())
{
Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\t列名: {property.Name} 类型: {property.ClrType.Name}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
}</span></pre>
</div>
<p>dc.Model.GetEntityTypes 方法能够返回模型中所有实体的信息。GetTableName 返回实体对应的数据表名,FindPrimaryKey 方法找出此实体类的主键。最后,GetProperties 方法获取实体类属性对应的列。</p>
<p>上述代码运行后得到的结果如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">表名: Pets,主键: id
列名: id 类型: Int32
列名: Age 类型: Int32
列名: Cate 类型: String
列名: Name 类型: String</span></pre>
</div>
<p>好,看来,小写的 id 属性是可以被识别为主键的(老周不再分析 EF Core 源代码了,不然这博文就没人看了,其实是通过约定实现的)。同理,我们还可以验证一下,全小写的 petid 能不能识别。把 Pet 类改为:</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)"> Pet
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> <span style="background-color: rgba(255, 255, 0, 1)">petid</span> { <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>至少咱们知道,PetId 是肯定能被识别为主键的,现在验证一下全小写的<类名>id的属性。再次运行程序,得到:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">表名: Pets,主键: <strong><span style="background-color: rgba(255, 255, 0, 1)">petid</span></strong>
列名: petid 类型: Int32
列名: Age 类型: Int32
列名: Cate 类型: String
列名: Name 类型: String<br></span></pre>
</div>
<p>这个示例证明:Id 和 <类名>Id 都能被约定识别为主键,并且<span style="color: rgba(0, 0, 128, 1)"><em><strong>不区分大小写</strong></em></span>。</p>
<p>那么,如果属性的名称不是 <类名>Id 呢,比如这样改:</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)"> Pet
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> <strong><span style="background-color: rgba(255, 255, 0, 1)">BugId</span> </strong>{ <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(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">.Empty;
</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>? Cate { <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>再次运行一下,结果不出所料。</p>
<p><img src="https://img2024.cnblogs.com/blog/367389/202507/367389-20250720130424889-1053376383.png" alt="" width="583" height="85" loading="lazy"></p>
<p>这段鸟语说了啥?它说 Pet 这厮必须定义主键,如果你不想要主键,那得<strong><span style="color: rgba(0, 0, 128, 1)">明确地把实体配置为无主键</span></strong>。怎么配置为无主键咱们后文再说,现在先说说“预制菜”约定无法自动识别出主键,咱们如何手动配置。</p>
<p>1、简单做法,用特性在 BugId 属性上批注一下。</p>
<div class="cnblogs_code">
<pre><strong><span style="color: rgba(0, 0, 0, 1); background-color: rgba(255, 255, 0, 1)">
</span></strong><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)"> Pet
{
</span><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 0, 255, 1)">……</span></span><span style="color: rgba(0, 0, 0, 1)">
}</span></pre>
</div>
<p>这种方法最简单,但老周个人不推荐,因为不集中配置,不好管理。当然,只是老周不推荐,没说不可以用啊。</p>
<p>2、通过 ModelBuilder 来配置,这个在 DbContext 的派生类中重写 OnModelCreating 方法。</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><span style="color: rgba(0, 0, 0, 1)"> OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity</span><Pet>().<span style="background-color: rgba(255, 255, 0, 1)"><strong>HasKey(x =></strong></span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)"><strong> x.BugId)</strong></span>;
}</span></pre>
</div>
<p>老周比较推荐这种方法,因为它把所有实体的配置全集中一处,将来有改动也好搞,也不容易忘这个忘那个的。两种方法任选其一,不需要同时用。</p>
<p>再次运行程序,看到想要的结果了。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">表名: Pets,<strong><span style="background-color: rgba(255, 255, 0, 1)">主键: BugId</span></strong>
列名: BugId 类型: Int32
列名: Age 类型: Int32
列名: Cate 类型: String
列名: Name 类型: String</span></pre>
</div>
<p> </p>
<p>有时候你可能会想:我的代码中并不需要访问主键,主键仅留给 EF 自己用于生成 SQL 语句,那我能不能把影子属性作为主键呢?答案是 Yes 的。先简单说说影子属性(Shadow Property)是什么,一句话斯基:你的<span style="color: rgba(0, 0, 128, 1)"><em><strong>实体类中未定义的,但模型中定义了的属性</strong></em></span>。</p>
<p>同理,你的 DbContext 子类需要重写 OnModelCreating 方法。</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><span style="color: rgba(0, 0, 0, 1)"> OnModelCreating(ModelBuilder modelBuilder)
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 这一行很重要</span>
modelBuilder.Entity<Pet>().<span style="background-color: rgba(255, 255, 0, 1)"><strong>Property(<span style="color: rgba(0, 0, 255, 1)">typeof</span>(<span style="color: rgba(0, 0, 255, 1)">int</span>), <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">HideId</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>
modelBuilder.Entity<Pet><span style="color: rgba(0, 0, 0, 1)">()
.HasKey(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">HideId</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}</span></pre>
</div>
<p>Pet 类可以去掉作为主键的属性。</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)"> Pet
{
</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(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">.Empty;
</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>? Cate { <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>由于影子属性在实体类未定义,EF Core 并不能确定其类型能不能成为主键。因此,在定义主键前应该让 EF 知道作为主键的影子属性是支持的类型,如 int。</p>
<div class="cnblogs_code">
<pre>modelBuilder.Entity<Pet>().Property(<span style="color: rgba(0, 0, 255, 1)">typeof</span>(<span style="color: rgba(0, 0, 255, 1)">int</span>), <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">HideId</span><span style="color: rgba(128, 0, 0, 1)">"</span>);</pre>
</div>
<p>上面的例子就是把影子属性 HideId 作为 Pet 实体的主键。运行结果如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">表名: Pets,<strong><span style="background-color: rgba(255, 255, 0, 1)">主键: HideId</span></strong>
列名: HideId 类型: Int32
列名: Age 类型: Int32
列名: Cate 类型: String
列名: Name 类型: String</span></pre>
</div>
<p>主键也可以由多个属性(列)组成。比如,咱们让 HideId 和 Name 组成主键。</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><span style="color: rgba(0, 0, 0, 1)"> OnModelCreating(ModelBuilder modelBuilder)
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 这一行很重要</span>
modelBuilder.Entity<Pet>().Property(<span style="color: rgba(0, 0, 255, 1)">typeof</span>(<span style="color: rgba(0, 0, 255, 1)">int</span>), <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">HideId</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>
modelBuilder.Entity<Pet><span style="color: rgba(0, 0, 0, 1)">()
.HasKey(</span><span style="background-color: rgba(255, 255, 0, 1)"><strong><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">HideId</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>, nameof(Pet.Name)</strong></span>);
}</span></pre>
</div>
<p>得到的运行结果如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">表名: Pets,<span style="background-color: rgba(255, 255, 0, 1)"><strong>主键: HideId, Name</strong></span>
列名: HideId 类型: Int32
列名: Name 类型: String
列名: Age 类型: Int32
列名: Cate 类型: String</span></pre>
</div>
<p> </p>
<p>下面咱们演示一下把 string 类型的属性映射到 SQL Server 数据表的 unique identifier 列。</p>
<p>1、用以下 SQL 脚本(使用的是 SQL Server)创建数据库和数据表。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)">--</span><span style="color: rgba(0, 128, 128, 1)"> 创建数据库</span>
<span style="color: rgba(0, 0, 255, 1)">CREATE</span> <span style="color: rgba(0, 0, 255, 1)">DATABASE</span><span style="color: rgba(0, 0, 0, 1)"> Test;
</span><span style="color: rgba(0, 0, 255, 1)">GO</span>
<span style="color: rgba(0, 128, 128, 1)">--</span><span style="color: rgba(0, 128, 128, 1)"> 切换到刚刚创建的数据库</span>
<span style="color: rgba(0, 0, 255, 1)">USE</span><span style="color: rgba(0, 0, 0, 1)"> Test;
</span><span style="color: rgba(0, 0, 255, 1)">GO</span>
<span style="color: rgba(0, 128, 128, 1)">--</span><span style="color: rgba(0, 128, 128, 1)"> 创建表</span>
<span style="color: rgba(0, 0, 255, 1)">CREATE</span> <span style="color: rgba(0, 0, 255, 1)">TABLE</span><span style="color: rgba(0, 0, 0, 1)"> Productions (
</span><span style="color: rgba(0, 128, 128, 1)">--</span><span style="color: rgba(0, 128, 128, 1)"> 这个是主键,插入时如果未提供值,则用 NEWID() 产生的值</span>
Pid <span style="color: rgba(0, 0, 255, 1)">UNIQUEIDENTIFIER</span> <span style="color: rgba(0, 0, 255, 1)">PRIMARY</span> <span style="color: rgba(0, 0, 255, 1)">KEY</span> <span style="color: rgba(0, 0, 255, 1)">DEFAULT</span> <span style="color: rgba(255, 0, 255, 1)">NEWID</span><span style="color: rgba(0, 0, 0, 1)">(),
</span><span style="color: rgba(0, 128, 128, 1)">--</span><span style="color: rgba(0, 128, 128, 1)"> 产品名称</span>
ProdName <span style="color: rgba(0, 0, 255, 1)">NVARCHAR</span>(<span style="color: rgba(128, 0, 0, 1); font-weight: bold">40</span>) <span style="color: rgba(128, 128, 128, 1)">NOT</span> <span style="color: rgba(0, 0, 255, 1)">NULL</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">--</span><span style="color: rgba(0, 128, 128, 1)"> 生产年份</span>
<span style="color: rgba(255, 0, 255, 1)">Year</span> <span style="color: rgba(0, 0, 255, 1)">INT</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">--</span><span style="color: rgba(0, 128, 128, 1)"> 产品尺寸</span>
Size <span style="color: rgba(0, 0, 255, 1)">DECIMAL</span>(<span style="color: rgba(128, 0, 0, 1); font-weight: bold">6</span>,<span style="color: rgba(128, 0, 0, 1); font-weight: bold">2</span><span style="color: rgba(0, 0, 0, 1)">),
</span><span style="color: rgba(0, 128, 128, 1)">--</span><span style="color: rgba(0, 128, 128, 1)"> 产品颜色</span>
Color <span style="color: rgba(0, 0, 255, 1)">NVARCHAR</span>(<span style="color: rgba(128, 0, 0, 1); font-weight: bold">10</span><span style="color: rgba(0, 0, 0, 1)">),
</span><span style="color: rgba(0, 128, 128, 1)">--</span><span style="color: rgba(0, 128, 128, 1)"> 备注</span>
Remark <span style="color: rgba(0, 0, 255, 1)">NVARCHAR</span>(<span style="color: rgba(255, 0, 255, 1)">MAX</span><span style="color: rgba(0, 0, 0, 1)">)
);</span></pre>
</div>
<p>2、创建控制台 .NET 项目(此处省略250个字)。</p>
<p>3、定义实体类(这个可以用 dotnet ef dbcontext 命令生成,不过老周一向习惯纯手写,生成的实体类有时候要回头修改)。</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)"> Production
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="background-color: rgba(255, 255, 0, 1)"><strong><span style="color: rgba(0, 0, 255, 1)">string</span> Pid {</strong> <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, 255, 1)">null</span>!</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> ProdName { <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, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">.Empty;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span>? Year { <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)">decimal</span>? Size { <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>? Color { <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>? Remark { <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>Pid 属性要作为主键用的,注意这里老周故意让其默认值为 null,这样在 EF 上下文添加实体时使用数据库生成的值(否则会报错)。null 后面有个感叹号(!)这个可以避免编译器的 Nullable 警告,具体情况你可以找微软官方文档,有详细说明。就是微软文档写得太好了,导致很多基础知识老周都不必重复介绍了。</p>
<p>4、派生 DbContext 的子类。</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)"> MyContext : DbContext
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> DbSet<Production> Productions { <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><span style="color: rgba(0, 0, 0, 1)"> OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 配置连接字符串</span>
optionsBuilder.UseSqlServer(<span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">Server=(localdb)\MSSQLLocalDB;Database=Test;Trusted_Connection=True</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)"> OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.<strong><span style="background-color: rgba(255, 255, 0, 1)">Entity</span></strong></span><strong><span style="background-color: rgba(255, 255, 0, 1)"><Production></span></strong>(entbd =><span style="color: rgba(0, 0, 0, 1)">
{
entbd.Property(p </span>=><span style="color: rgba(0, 0, 0, 1)"> p.Pid)
.ValueGeneratedOnAdd();
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 产品名称为必须,且有长度限制</span>
entbd.Property(p =><span style="color: rgba(0, 0, 0, 1)"> p.ProdName)
.IsRequired()
.HasMaxLength(</span><span style="color: rgba(128, 0, 128, 1)">40</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>
entbd.Property(p =><span style="color: rgba(0, 0, 0, 1)"> p.Size)
.HasPrecision(</span><span style="color: rgba(128, 0, 128, 1)">6</span>, <span style="color: rgba(128, 0, 128, 1)">2</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>
entbd.Property(p =><span style="color: rgba(0, 0, 0, 1)"> p.Color)
.HasMaxLength(</span><span style="color: rgba(128, 0, 128, 1)">10</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>
entbd.HasKey(p =><span style="color: rgba(0, 0, 0, 1)"> p.Pid);
});
}
}</span></pre>
</div>
<p>ModelBuilder 的 Entity 方法可以获得一个 EntityTypeBuilder 对象(上面老周是调用了带 Action 委托的重载,方便多次调用 EntityTypeBuilder 实例的成员)。EntityTypeBuilder 类内部封装了 InternalEntityTypeBuilder 对象,各种配置方法实际调用了此 InternalEntityTypeBuilder 对象的成员。</p>
<p>5、在 Program.cs 文件中,写一下测试代码。咱们向数据库存入两条记录。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 实例化上下文</span>
MyContext dc = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> MyContext();
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 新建两条记录</span>
Production p1 = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)">()
{
ProdName </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)">,
Year </span>= <span style="color: rgba(128, 0, 128, 1)">2025</span><span style="color: rgba(0, 0, 0, 1)">,
Size </span>= <span style="color: rgba(128, 0, 128, 1)">67.33m</span><span style="color: rgba(0, 0, 0, 1)">,
Color </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)">,
Remark </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)">
};
Production p2 </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)">()
{
ProdName </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)">,
Year </span>= <span style="color: rgba(128, 0, 128, 1)">2025</span><span style="color: rgba(0, 0, 0, 1)">,
Size </span>= <span style="color: rgba(128, 0, 128, 1)">47.00m</span><span style="color: rgba(0, 0, 0, 1)">,
Color </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)">,
Remark </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)">
};
dc.Productions.AddRange(p1, p2);
</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, 0, 1)">dc.SaveChanges();
dc.Dispose();</span></pre>
</div>
<p>如果代码顺利运行,则数据库中就有两条新记录了。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">select</span> <span style="color: rgba(128, 128, 128, 1)">*</span> <span style="color: rgba(0, 0, 255, 1)">from</span> dbo.Productions</pre>
</div>
<p><img src="https://img2024.cnblogs.com/blog/367389/202507/367389-20250720185422539-1454423486.png" alt="" width="758" height="57" loading="lazy"></p>
<p>当然了,对于 UNIQUE IDENTIFIER 类型的主键,.NET CLR 实体类的属性除了可以用字符串类型,也可以用 Guid 类型。原理也是一样的,这里老周就不演示了,相信大伙伴们都会的。</p>
<p>===========================================================================================================</p>
<p> 接下来看看无主键的实体。这个其实没什么特别的知识要掌握的,但你得记住一条:无主键的实体只能 SELECT,不能用于 INSERT、UPDATE、DELETE 操作。一句话斯基总结就是:<span style="color: rgba(0, 0, 128, 1)"><strong>只能查询不能更新</strong></span>。</p>
<p>咱们还是整个例子吧。</p>
<p>1、用以下SQL脚本创建数据库和数据表。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">create</span> <span style="color: rgba(0, 0, 255, 1)">database</span><span style="color: rgba(0, 0, 0, 1)"> DemoSome;
</span><span style="color: rgba(0, 0, 255, 1)">GO</span>
<span style="color: rgba(0, 0, 255, 1)">use</span><span style="color: rgba(0, 0, 0, 1)"> DemoSome;
</span><span style="color: rgba(0, 0, 255, 1)">GO</span>
<span style="color: rgba(0, 128, 128, 1)">--</span><span style="color: rgba(0, 128, 128, 1)"> 创建表</span>
<span style="color: rgba(0, 0, 255, 1)">create</span> <span style="color: rgba(0, 0, 255, 1)">table</span><span style="color: rgba(0, 0, 0, 1)"> HandsomeBoys
(
BoyID </span><span style="color: rgba(0, 0, 255, 1)">int</span> <span style="color: rgba(255, 0, 255, 1)">IDENTITY</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Name</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">NVARCHAR</span>(<span style="color: rgba(128, 0, 0, 1); font-weight: bold">25</span>) <span style="color: rgba(128, 128, 128, 1)">not</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">,
Age </span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">,
City </span><span style="color: rgba(0, 0, 255, 1)">NVARCHAR</span>(<span style="color: rgba(128, 0, 0, 1); font-weight: bold">10</span><span style="color: rgba(0, 0, 0, 1)">),
PhoneNo </span><span style="color: rgba(0, 0, 255, 1)">NVARCHAR</span>(<span style="color: rgba(128, 0, 0, 1); font-weight: bold">11</span><span style="color: rgba(0, 0, 0, 1)">),
Email </span><span style="color: rgba(0, 0, 255, 1)">NVARCHAR</span>(<span style="color: rgba(128, 0, 0, 1); font-weight: bold">40</span><span style="color: rgba(0, 0, 0, 1)">),
</span><span style="color: rgba(0, 0, 255, 1)">CONSTRAINT</span> <span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">PK_HandsomeBoys</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">PRIMARY</span> <span style="color: rgba(0, 0, 255, 1)">KEY</span> <span style="color: rgba(0, 0, 255, 1)">CLUSTERED</span> (BoyID <span style="color: rgba(0, 0, 255, 1)">ASC</span><span style="color: rgba(0, 0, 0, 1)">)
);
</span><span style="color: rgba(0, 0, 255, 1)">GO</span></pre>
</div>
<p>2、向数据表 INSERT 几条数据用于测试,随便写,略。</p>
<p>3、创建.NET控制台应用程序,略。</p>
<p>4、定义实体类(可以用 dotnet ef 工具生成,也可以纯手打)。</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)"> HandsomBoy
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> ID { <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(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">.Empty;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span>? Email { <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>? City { <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)">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>? PhoneNo { <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>5、写数据库上下文类,构建模型。</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)"> DemoDB : DbContext
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> DemoDB(DbContextOptions<DemoDB><span style="color: rgba(0, 0, 0, 1)"> options)
:</span><span style="color: rgba(0, 0, 255, 1)">base</span><span style="color: rgba(0, 0, 0, 1)">(options) { }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> DbSet<HandsomBoy> HandsomeBoys { <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><span style="color: rgba(0, 0, 0, 1)"> OnModelCreating(ModelBuilder modelBuilder)
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 无主键</span>
<strong><span style="background-color: rgba(255, 255, 0, 1)"> modelBuilder.Entity<HandsomBoy><span style="color: rgba(0, 0, 0, 1)">().HasNoKey();
</span></span></strong> <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)">var</span> entbd = modelBuilder.Entity<HandsomBoy>().ToTable(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">HandsomeBoys</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>
entbd.Property(p => p.ID).HasColumnName(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">BoyID</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
entbd.Property(p </span>=><span style="color: rgba(0, 0, 0, 1)"> p.Name)
.IsRequired()
.HasMaxLength(</span><span style="color: rgba(128, 0, 128, 1)">25</span><span style="color: rgba(0, 0, 0, 1)">);
entbd.Property(p </span>=> p.City).HasMaxLength(<span style="color: rgba(128, 0, 128, 1)">10</span><span style="color: rgba(0, 0, 0, 1)">);
entbd.Property(p </span>=> p.Email).HasMaxLength(<span style="color: rgba(128, 0, 128, 1)">40</span><span style="color: rgba(0, 0, 0, 1)">);
entbd.Property(p </span>=> p.PhoneNo).HasMaxLength(<span style="color: rgba(128, 0, 128, 1)">11</span><span style="color: rgba(0, 0, 0, 1)">);
}
}</span></pre>
</div>
<p>注意要调用 HasNoKey 方法配置实体为无主键,不然会报错。</p>
<p>6、测试。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 配置选项</span>
DbContextOptions<DemoDB> options = <span style="color: rgba(0, 0, 255, 1)">new</span> DbContextOptionsBuilder<DemoDB><span style="color: rgba(0, 0, 0, 1)">()
.UseSqlServer(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Server=(localdb)\\MSSQLLocalDB;Database=DemoSome;Trusted_Connection=True</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>
.LogTo(msg =><span style="color: rgba(0, 0, 0, 1)"> Console.WriteLine(msg))
.EnableSensitiveDataLogging()
.Options;
</span><span style="color: rgba(0, 0, 255, 1)">using</span> <span style="color: rgba(0, 0, 255, 1)">var</span> dc = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> DemoDB(options);
</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)">var</span> q = <span style="color: rgba(0, 0, 255, 1)">from</span> b <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> dc.HandsomeBoys
</span><span style="color: rgba(0, 0, 255, 1)">select</span><span style="color: rgba(0, 0, 0, 1)"> b;
</span><span style="color: rgba(0, 0, 255, 1)">foreach</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> x <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> q)
{
Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">ID={x.ID}, Name={x.Name}, Age={x.Age}, City={x.City}, Phone={x.PhoneNo}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}</span></pre>
</div>
<p>结果如下:</p>
<div class="cnblogs_code">
<pre>ID=<span style="color: rgba(128, 0, 128, 1)">1</span>, Name=小陈, Age=<span style="color: rgba(128, 0, 128, 1)">35</span>, City=珠海, Phone=<span style="color: rgba(128, 0, 128, 1)">15562021200</span><span style="color: rgba(0, 0, 0, 1)">
ID</span>=<span style="color: rgba(128, 0, 128, 1)">2</span>, Name=老周, Age=<span style="color: rgba(128, 0, 128, 1)">105</span>, City=东莞, Phone=<span style="color: rgba(128, 0, 128, 1)">13888582588</span><span style="color: rgba(0, 0, 0, 1)">
ID</span>=<span style="color: rgba(128, 0, 128, 1)">3</span>, Name=老丁, Age=<span style="color: rgba(128, 0, 128, 1)">45</span>, City=中山, Phone=<span style="color: rgba(128, 0, 128, 1)">15840991234</span></pre>
</div>
<p>无主键实体也可以用特性批注。</p>
<div class="cnblogs_code">
<pre><strong><span style="color: rgba(0, 0, 0, 1); background-color: rgba(255, 255, 0, 1)">
</span></strong><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)"> HandsomBoy
{
……
}</span></pre>
</div>
<p>两种方法,二选一。</p>
<p>好了,今天就聊到这儿了。</p>
<p> </p><br><br>
来源:https://www.cnblogs.com/tcjiaan/p/18993171
頁:
[1]