风行正义 發表於 2025-9-13 16:32:00

【EF Core】再谈普通实体关系与 Owned 关系的区别

<p>在很多个世纪前,老周曾写过实体之间普通关系(一对一,一对多,多对多)与 Owned 关系的区别。不过,那次写得比较粗浅,逼格不够高,于是,老周厚着脸皮地决定重新写一下。</p>
<p>首先,为什么这次老周用原单词 Owned 呢,官方文档目前的翻译(怀疑是机器干的)为“从属”,这种说法与普通关系数据库中一对多、多对多等关系描述不太 好区分。其实老周觉得应该把 Owned 翻译为“独占”关系——你完全属于我的。普通关系中的厕所是公共厕所,我可以用,邻居A、B、C也可以用;而 Owned 关系中的厕所是私人的,我用我家的厕所,A用A家自己的厕所,B不能用A家的厕所。</p>
<p>这种玩意儿比某少年马戏团的粉丝还抽象,要理解最好的方法是比较。本文老周就对这两类关系做一轮大比拼。</p>
<h3>One and One</h3>
<p>首先我们来看“一”和“一”的方式。为了保持数据结构的一致,咱们用这三个实体来实验。</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)"> HardwareInfo
{
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> HwID { <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, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 主键</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">long</span> MemorySize { <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, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 内存大小</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> HarddiskNum { <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, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 硬盘数量</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">long</span> HDDSize { <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, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 硬盘大小</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">bool</span> InteGrp { <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, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 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)">class</span><span style="color: rgba(0, 0, 0, 1)"> Desktop
{
    </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, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 主键</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> HardwareInfo HWInfo { <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, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 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)">class</span><span style="color: rgba(0, 0, 0, 1)"> Laptop
{
    </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, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 主键</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> HardwareInfo HWInfo { <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, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 硬件信息</span>
}</pre>
</div>
<p>HardwareInfo 表示硬件参数,不管是台式机(Desktop)还是笔记本(Laptop)都可以共用这样的数据结构。</p>
<p>先定义用在普通关系的上下文类——MyContextR,R结尾表示 Relational。</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)"> MyContextR : DbContext
{
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> DbSet&lt;Desktop&gt; PCs { <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> DbSet&lt;Laptop&gt; Laps { <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)
    {
      optionsBuilder.UseSqlServer(</span><span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">server=&lt;你的服务器&gt;;database=rdb</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
      <strong><span style="background-color: rgba(255, 255, 0, 1)">.LogTo(m </span></strong></span><strong><span style="background-color: rgba(255, 255, 0, 1)">=&gt;</span></strong><span style="color: rgba(0, 0, 0, 1)"><strong><span style="background-color: rgba(255, 255, 0, 1)"> Debug.WriteLine(m))</span></strong>;
    }

    </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 mb)
    {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 配置主键</span>
      mb.Entity&lt;HardwareInfo&gt;().HasKey(m =&gt;<span style="color: rgba(0, 0, 0, 1)"> m.HwID);

      mb.Entity</span>&lt;Laptop&gt;(ent =&gt;<span style="color: rgba(0, 0, 0, 1)">
      {
            ent.HasKey(k </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> k.ID);
            <span style="background-color: rgba(255, 255, 0, 1)">ent.HasOne(x </span></span><span style="background-color: rgba(255, 255, 0, 1)">=&gt;</span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)"> x.HWInfo);</span>
      });
      mb.Entity</span>&lt;Desktop&gt;(eb =&gt;<span style="color: rgba(0, 0, 0, 1)">
      {
            eb.HasKey(a </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> a.ID);
            <span style="background-color: rgba(255, 255, 0, 1)">eb.HasOne(y </span></span><span style="background-color: rgba(255, 255, 0, 1)">=&gt;</span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)"> y.HWInfo);</span>
      });
    }
}</span></pre>
</div>
<p>由于老周在定义实体类时“粗心大意”,主键属性的命名无法让 EF Core 自动识别,所以要在 OnModelCreating 方法中显式配置一下。注意,HasOne 让它们建立一对一的关系,即PC有一个HardwareInfo 实例,笔记本也有。</p>
<p>第二个上下文类是面向“独占”关系的 MyContextO,O 结尾表示 Owned。</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)"> MyContextO : DbContext
{
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> DbSet&lt;Laptop&gt; Laps { <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> DbSet&lt;Desktop&gt; PCs { <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)
    {
      optionsBuilder.UseSqlServer(</span><span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">server=&lt;你的服务器&gt;;database=odb</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
      .LogTo(g </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> Debug.WriteLine(g));
    }

    </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 mb)
    {
      mb.Entity</span>&lt;Laptop&gt;().HasKey(m =&gt;<span style="color: rgba(0, 0, 0, 1)"> m.ID);
      mb.Entity</span>&lt;Desktop&gt;().HasKey(n =&gt;<span style="color: rgba(0, 0, 0, 1)"> n.ID);
      mb.Entity</span>&lt;Laptop&gt;().<span style="background-color: rgba(255, 255, 0, 1)">OwnsOne(x =&gt;</span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)"> x.HWInfo)</span>;
      mb.Entity</span>&lt;Desktop&gt;().<span style="background-color: rgba(255, 255, 0, 1)">OwnsOne(w =&gt;</span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)"> w.HWInfo)</span>;
    }
}</span></pre>
</div>
<p>OwnsOne 表示一占一,PC占用一个HardwareInfo实例,笔记本也占用一个,两者不相干。这种情形 HardwareInfo 是不需要主键的,为什么?往下看你就懂了。</p>
<p>咱们依次实例化这两个上下文对象,然后让它自己创建数据库。</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><span style="color: rgba(0, 0, 255, 1)">using</span> MyContextR c1 = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)">();
    c1.Database.EnsureCreated();

    </span><span style="color: rgba(0, 0, 255, 1)">using</span> MyContextO c2 = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)">();
    c2.Database.EnsureCreated();
}</span></pre>
</div>
<p>实验结果发现,普通一对一关系中,创建了三个表:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">CREATE</span> <span style="color: rgba(0, 0, 255, 1)">TABLE</span> <span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HardwareInfo</span><span style="color: rgba(255, 0, 0, 1)">]</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)">HwID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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(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)">MemorySize</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">bigint</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HarddiskNum</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HDDSize</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">bigint</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">InteGrp</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">bit</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, 0, 255, 1)">CONSTRAINT</span> <span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">PK_HardwareInfo</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HwID</span><span style="color: rgba(255, 0, 0, 1)">]</span><span style="color: rgba(0, 0, 0, 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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Laps</span><span style="color: rgba(255, 0, 0, 1)">]</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)">ID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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(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)">HWInfoHwID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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, 0, 255, 1)">CONSTRAINT</span> <span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">PK_Laps</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">ID</span><span style="color: rgba(255, 0, 0, 1)">]</span><span style="color: rgba(0, 0, 0, 1)">),
    </span><span style="color: rgba(0, 0, 255, 1)">CONSTRAINT</span> <span style="background-color: rgba(255, 255, 0, 1)"><span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">FK_Laps_HardwareInfo_HWInfoHwID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">FOREIGN</span> <span style="color: rgba(0, 0, 255, 1)">KEY</span> (<span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HWInfoHwID</span><span style="color: rgba(255, 0, 0, 1)">]</span>) <span style="color: rgba(0, 0, 255, 1)">REFERENCES</span> <span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HardwareInfo</span><span style="color: rgba(255, 0, 0, 1)">]</span> (<span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HwID</span><span style="color: rgba(255, 0, 0, 1)">]</span></span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)">)</span>
);

</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">PCs</span><span style="color: rgba(255, 0, 0, 1)">]</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)">ID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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(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)">HWInfoHwID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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, 0, 255, 1)">CONSTRAINT</span> <span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">PK_PCs</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">ID</span><span style="color: rgba(255, 0, 0, 1)">]</span><span style="color: rgba(0, 0, 0, 1)">),
    </span><span style="color: rgba(0, 0, 255, 1)">CONSTRAINT</span> <span style="background-color: rgba(255, 255, 0, 1)"><span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">FK_PCs_HardwareInfo_HWInfoHwID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">FOREIGN</span> <span style="color: rgba(0, 0, 255, 1)">KEY</span> (<span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HWInfoHwID</span><span style="color: rgba(255, 0, 0, 1)">]</span>) <span style="color: rgba(0, 0, 255, 1)">REFERENCES</span> <span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HardwareInfo</span><span style="color: rgba(255, 0, 0, 1)">]</span> (<span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HwID</span><span style="color: rgba(255, 0, 0, 1)">]</span></span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)">)</span>
);</span></pre>
</div>
<p>EF Core 这货还挺聪明的,把外键分别放在 Desktop 和 Laptop 中,这样可避免在 HardwareInfo 中出现两个外键,不好约束。毕竟这是一对一关系,外键放在哪一端都可以。</p>
<p>然后看看“独占”关系中的一对一,它创建了两个表:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">CREATE</span> <span style="color: rgba(0, 0, 255, 1)">TABLE</span> <span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Laps</span><span style="color: rgba(255, 0, 0, 1)">]</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)">ID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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(255, 0, 255, 1)">IDENTITY</span><span style="color: rgba(0, 0, 0, 1)">,
    </span><span style="background-color: rgba(255, 255, 0, 1)"><span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HWInfo_HwID</span><span style="color: rgba(255, 0, 0, 1)">]</span></span> <span style="color: rgba(0, 0, 255, 1)">int</span> <span style="color: rgba(0, 0, 255, 1)">NULL</span><span style="color: rgba(0, 0, 0, 1)">,
    </span><span style="background-color: rgba(255, 255, 0, 1)"><span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HWInfo_MemorySize</span><span style="color: rgba(255, 0, 0, 1)">]</span></span> <span style="color: rgba(0, 0, 255, 1)">bigint</span> <span style="color: rgba(0, 0, 255, 1)">NULL</span><span style="color: rgba(0, 0, 0, 1)">,
    </span><span style="background-color: rgba(255, 255, 0, 1)"><span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HWInfo_HarddiskNum</span><span style="color: rgba(255, 0, 0, 1)">]</span></span> <span style="color: rgba(0, 0, 255, 1)">int</span> <span style="color: rgba(0, 0, 255, 1)">NULL</span><span style="color: rgba(0, 0, 0, 1)">,
    </span><span style="background-color: rgba(255, 255, 0, 1)"><span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HWInfo_HDDSize</span><span style="color: rgba(255, 0, 0, 1)">]</span></span> <span style="color: rgba(0, 0, 255, 1)">bigint</span> <span style="color: rgba(0, 0, 255, 1)">NULL</span><span style="color: rgba(0, 0, 0, 1)">,
    </span><span style="background-color: rgba(255, 255, 0, 1)"><span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HWInfo_InteGrp</span><span style="color: rgba(255, 0, 0, 1)">]</span></span> <span style="color: rgba(0, 0, 255, 1)">bit</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, 0, 255, 1)">CONSTRAINT</span> <span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">PK_Laps</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">ID</span><span style="color: rgba(255, 0, 0, 1)">]</span><span style="color: rgba(0, 0, 0, 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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">PCs</span><span style="color: rgba(255, 0, 0, 1)">]</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)">ID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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(255, 0, 255, 1)">IDENTITY</span><span style="color: rgba(0, 0, 0, 1)">,
    </span><span style="background-color: rgba(255, 255, 0, 1)"><span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HWInfo_HwID</span><span style="color: rgba(255, 0, 0, 1)">]</span></span> <span style="color: rgba(0, 0, 255, 1)">int</span> <span style="color: rgba(0, 0, 255, 1)">NULL</span><span style="color: rgba(0, 0, 0, 1)">,
    </span><span style="background-color: rgba(255, 255, 0, 1)"><span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HWInfo_MemorySize</span><span style="color: rgba(255, 0, 0, 1)">]</span></span> <span style="color: rgba(0, 0, 255, 1)">bigint</span> <span style="color: rgba(0, 0, 255, 1)">NULL</span><span style="color: rgba(0, 0, 0, 1)">,
    </span><span style="background-color: rgba(255, 255, 0, 1)"><span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HWInfo_HarddiskNum</span><span style="color: rgba(255, 0, 0, 1)">]</span></span> <span style="color: rgba(0, 0, 255, 1)">int</span> <span style="color: rgba(0, 0, 255, 1)">NULL</span><span style="color: rgba(0, 0, 0, 1)">,
    </span><span style="background-color: rgba(255, 255, 0, 1)"><span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HWInfo_HDDSize</span><span style="color: rgba(255, 0, 0, 1)">]</span></span> <span style="color: rgba(0, 0, 255, 1)">bigint</span> <span style="color: rgba(0, 0, 255, 1)">NULL</span><span style="color: rgba(0, 0, 0, 1)">,
    </span><span style="background-color: rgba(255, 255, 0, 1)"><span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HWInfo_InteGrp</span><span style="color: rgba(255, 0, 0, 1)">]</span></span> <span style="color: rgba(0, 0, 255, 1)">bit</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, 0, 255, 1)">CONSTRAINT</span> <span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">PK_PCs</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">ID</span><span style="color: rgba(255, 0, 0, 1)">]</span><span style="color: rgba(0, 0, 0, 1)">)
);</span></pre>
</div>
<p>你没看错,只有两个表,HardwareInfo 直接被拆开了,Desktop和Laptop各拥有一份。现在你明白了吧,为什么 HardwareInfo 在这种关系下不需要主键,因为它们不独成表。</p>
<p>那么,如果让 HardwareInfo 独立建表呢,又会怎样?咱们把 MyContextO 类的代码改一下,为 HardwareInfo 类单独建表。</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)"> MyContextO : DbContext
{
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> DbSet&lt;Laptop&gt; Laps { <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> DbSet&lt;Desktop&gt; PCs { <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 mb)
    {
      mb.Entity</span>&lt;Desktop&gt;(et =&gt;<span style="color: rgba(0, 0, 0, 1)">
      {
            et.HasKey(a </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> a.ID);
            et.OwnsOne(b </span>=&gt; b.HWInfo, ob =&gt;<span style="color: rgba(0, 0, 0, 1)">
            {
                <span style="background-color: rgba(255, 255, 0, 1)">ob.ToTable(</span></span><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)">Desktop_HW</span><span style="color: rgba(128, 0, 0, 1)">"</span></span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)">);</span>
                ob.WithOwner();
            });
      });
      mb.Entity</span>&lt;Laptop&gt;(et =&gt;<span style="color: rgba(0, 0, 0, 1)">
      {
            et.HasKey(a </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> a.ID);
            et.OwnsOne(m </span>=&gt; m.HWInfo, ob =&gt;<span style="color: rgba(0, 0, 0, 1)">
            {
                <span style="background-color: rgba(255, 255, 0, 1)">ob.ToTable(</span></span><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)">Laptop_HW</span><span style="color: rgba(128, 0, 0, 1)">"</span></span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)">);</span>
                ob.WithOwner();
            });
      });
    }
}</span></pre>
</div>
<p>这个地方,WithOwner 方法可以不调用,因为 HardwareInfo 类没有定义指向 Laptop 或 Desktop 的反向导航属性。</p>
<p>这一次,会创建四个表:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">CREATE</span> <span style="color: rgba(0, 0, 255, 1)">TABLE</span> <span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Desktop_HW</span><span style="color: rgba(255, 0, 0, 1)">]</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)">DesktopID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HwID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">MemorySize</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">bigint</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HarddiskNum</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HDDSize</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">bigint</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">InteGrp</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">bit</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, 0, 255, 1)">CONSTRAINT</span> <span style="background-color: rgba(255, 255, 0, 1)"><span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">PK_Desktop_HW</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">DesktopID</span><span style="color: rgba(255, 0, 0, 1)">]</span></span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)">)</span>,
    </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)">FK_Desktop_HW_PCs_DesktopID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">FOREIGN</span> <span style="color: rgba(0, 0, 255, 1)">KEY</span> (<span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">DesktopID</span><span style="color: rgba(255, 0, 0, 1)">]</span>) <span style="color: rgba(0, 0, 255, 1)">REFERENCES</span> <span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">PCs</span><span style="color: rgba(255, 0, 0, 1)">]</span> (<span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">ID</span><span style="color: rgba(255, 0, 0, 1)">]</span>) <span style="color: rgba(0, 0, 255, 1)">ON</span> <span style="color: rgba(0, 0, 255, 1)">DELETE</span> <span style="color: rgba(0, 0, 255, 1)">CASCADE</span><span style="color: rgba(0, 0, 0, 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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Laptop_HW</span><span style="color: rgba(255, 0, 0, 1)">]</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)">LaptopID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HwID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">MemorySize</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">bigint</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HarddiskNum</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">HDDSize</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">bigint</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">InteGrp</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">bit</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, 0, 255, 1)">CONSTRAINT</span> <span style="background-color: rgba(255, 255, 0, 1)"><span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">PK_Laptop_HW</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">LaptopID</span><span style="color: rgba(255, 0, 0, 1)">]</span></span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)">)</span>,
    </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)">FK_Laptop_HW_Laps_LaptopID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">FOREIGN</span> <span style="color: rgba(0, 0, 255, 1)">KEY</span> (<span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">LaptopID</span><span style="color: rgba(255, 0, 0, 1)">]</span>) <span style="color: rgba(0, 0, 255, 1)">REFERENCES</span> <span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Laps</span><span style="color: rgba(255, 0, 0, 1)">]</span> (<span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">ID</span><span style="color: rgba(255, 0, 0, 1)">]</span>) <span style="color: rgba(0, 0, 255, 1)">ON</span> <span style="color: rgba(0, 0, 255, 1)">DELETE</span> <span style="color: rgba(0, 0, 255, 1)">CASCADE</span><span style="color: rgba(0, 0, 0, 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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">PCs</span><span style="color: rgba(255, 0, 0, 1)">]</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)">ID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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(255, 0, 255, 1)">IDENTITY</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_PCs</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">ID</span><span style="color: rgba(255, 0, 0, 1)">]</span><span style="color: rgba(0, 0, 0, 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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Laps</span><span style="color: rgba(255, 0, 0, 1)">]</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)">ID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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(255, 0, 255, 1)">IDENTITY</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_Laps</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">ID</span><span style="color: rgba(255, 0, 0, 1)">]</span><span style="color: rgba(0, 0, 0, 1)">)
);</span></pre>
</div>
<p>EF Core 很有才,咱们没有为 HardwareInfo 定义主键,于是它自己生成了,在 Laptop_HW 表中生成&nbsp;LaptopID 列作为主键,同时也作为外键,引用 Laptop.ID;在&nbsp;Desktop_HW 表中生成了&nbsp;DesktopID 列作为主键,同时作为外键,引用 Desktop.ID。</p>
<p>还要补充解释一下模型配置代码。</p>
<div class="cnblogs_code">
<pre> mb.Entity&lt;Laptop&gt;(et =&gt;<span style="color: rgba(0, 0, 0, 1)">
{
   et.HasKey(a </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> a.ID);
   et.OwnsOne(m </span>=&gt; m.HWInfo, ob =&gt;<span style="color: rgba(0, 0, 0, 1)">
   {
         <span style="background-color: rgba(255, 255, 0, 1)">ob.ToTable(</span></span><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)">Laptop_HW</span><span style="color: rgba(128, 0, 0, 1)">"</span></span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)">)</span>;
         </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">ob.WithOwner();</span>
<span style="color: rgba(0, 0, 0, 1)">   });
});</span></pre>
</div>
<p>ToTable 的调用在此处是必须的,否则按默认约定,它会使用表名 Laps,即和 Laptop 保持一致,这会导致出错。而且,Laptop 和 Desktop 不能共享一个 HardwareInfo 实体。这样配置也会报错:</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 mb)
{
    mb.Entity</span>&lt;Desktop&gt;(et =&gt;<span style="color: rgba(0, 0, 0, 1)">
    {
      et.HasKey(a </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> a.ID);
      et.OwnsOne(b </span>=&gt; b.HWInfo, ob =&gt;<span style="color: rgba(0, 0, 0, 1)">
      {
            ob.<span style="background-color: rgba(255, 255, 0, 1)">ToTable(</span></span><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)">HW_info</span><span style="color: rgba(128, 0, 0, 1)">"</span></span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)">)</span>;
      });
    });
    mb.Entity</span>&lt;Laptop&gt;(et =&gt;<span style="color: rgba(0, 0, 0, 1)">
    {
      et.HasKey(a </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> a.ID);
      et.OwnsOne(m </span>=&gt; m.HWInfo, ob =&gt;<span style="color: rgba(0, 0, 0, 1)">
      {
            ob.<span style="background-color: rgba(255, 255, 0, 1)">ToTable(</span></span><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)">HW_info</span><span style="color: rgba(128, 0, 0, 1)">"</span></span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)">)</span>;
      });
    });
}</span></pre>
</div>
<p>这就等于 Desktop 和 Laptop 同时占有相同的 HardwareInfo 实例,运行时也会报错。</p>
<p>&nbsp;</p>
<h3>One and Many</h3>
<p>&nbsp;这里咱们已经没有必要再与普通的一对多关系对比了,上面的对比已经明确 Owned 关系是独占性的,不共享实例。下面咱们看看实体独占多个实例的情况。这种情况下,被占有的对象不会与主对象共用一个表了——拆分的列无法表示多个实例。</p>
<p>举个例子。</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)"> AddressInfo
{
    </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
    <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 这里有主键
    </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> AddrID {<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(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
    <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 省
    </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Province { <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(0, 0, 0, 1)">;
    </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
    <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 市
    </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</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(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
    <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 镇
    </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Town { <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(0, 0, 0, 1)">;
    </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
    <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 路
    </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Road { <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(0, 0, 0, 1)">;
    </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
    <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 街道
    </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Street { <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(0, 0, 0, 1)">;
    </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
    <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 邮编
    </span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span>? ZipCode { <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)"> Student
{
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> StudentID { <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> IList&lt;AddressInfo&gt;? Addresses { <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>然后,上下文类是这样的。</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&lt;Student&gt; Students { <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 ob)
    {
      SqlConnectionStringBuilder strbd </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)">();
      strbd.DataSource </span>= <span style="color: rgba(128, 0, 0, 1)">&lt;你的服务器&gt;</span><span style="color: rgba(0, 0, 0, 1)">;
      strbd.InitialCatalog </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">TestDB</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
      ob.UseSqlServer(strbd.ConnectionString)
            .LogTo(x </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> Console.WriteLine(x));
    }

    </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.Entity</span>&lt;Student&gt;(ste =&gt;<span style="color: rgba(0, 0, 0, 1)">
      {
            ste.HasKey(x </span>=&gt; x.StudentID).HasName(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">PK_Stu_id</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)"> 它占有多个 Addr</span>
            ste.OwnsMany(k =&gt; k.Addresses, ob =&gt;<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="background-color: rgba(255, 255, 0, 1)">ob.HasKey(x =&gt;</span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)"> x.AddrID)</span>;
                ob.WithOwner()
                  .HasForeignKey(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">stu_id</span><span style="color: rgba(128, 0, 0, 1)">"</span>).HasConstraintName(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">FK_StuID</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><span style="color: rgba(0, 0, 255, 1)">CREATE</span> <span style="color: rgba(0, 0, 255, 1)">TABLE</span> <span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Students</span><span style="color: rgba(255, 0, 0, 1)">]</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)">StudentID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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(255, 0, 255, 1)">IDENTITY</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_Stu_id</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">StudentID</span><span style="color: rgba(255, 0, 0, 1)">]</span><span style="color: rgba(0, 0, 0, 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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">AddressInfo</span><span style="color: rgba(255, 0, 0, 1)">]</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)">AddrID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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(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)">Province</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">nvarchar</span>(<span style="color: rgba(255, 0, 255, 1)">max</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">City</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">nvarchar</span>(<span style="color: rgba(255, 0, 255, 1)">max</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Town</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">nvarchar</span>(<span style="color: rgba(255, 0, 255, 1)">max</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Road</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">nvarchar</span>(<span style="color: rgba(255, 0, 255, 1)">max</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Street</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">nvarchar</span>(<span style="color: rgba(255, 0, 255, 1)">max</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">ZipCode</span><span style="color: rgba(255, 0, 0, 1)">]</span> <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, 255, 1)">NULL</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)">stu_id</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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, 0, 255, 1)">CONSTRAINT</span> <span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">PK_AddressInfo</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">AddrID</span><span style="color: rgba(255, 0, 0, 1)">]</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)">FK_StuID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">FOREIGN</span> <span style="color: rgba(0, 0, 255, 1)">KEY</span> <strong><span style="background-color: rgba(255, 255, 0, 1)">(<span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">stu_id</span><span style="color: rgba(255, 0, 0, 1)">]</span>) <span style="color: rgba(0, 0, 255, 1)">REFERENCES</span> <span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Students</span><span style="color: rgba(255, 0, 0, 1)">]</span> (<span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">StudentID</span><span style="color: rgba(255, 0, 0, 1)">]</span>)</span></strong> <span style="color: rgba(0, 0, 255, 1)">ON</span> <span style="color: rgba(0, 0, 255, 1)">DELETE</span> <span style="color: rgba(0, 0, 255, 1)">CASCADE</span><span style="color: rgba(0, 0, 0, 1)">
      );</span></pre>
</div>
<p>AddressInfo 表会创建一个外键来引用 Students 表的主键列。</p>
<p>接着,咱们加一个 Teacher 实体,和学生一样,老师也有多个收货地址。</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)"> Teacher
{
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> Tid { <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> IList&lt;AddressInfo&gt;? Addresses { <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>
<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&lt;Student&gt; Students { <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="background-color: rgba(255, 255, 0, 1)"><span style="color: rgba(0, 0, 255, 1)">public</span> DbSet&lt;Teacher&gt; Teachers { <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><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>&lt;Student&gt;(ste =&gt;<span style="color: rgba(0, 0, 0, 1)">
      {
            ste.HasKey(x </span>=&gt; x.StudentID).HasName(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">PK_Stu_id</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)"> 它占有多个 Addr</span>
            ste.OwnsMany(k =&gt; k.Addresses, ob =&gt;<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>
                ob.HasKey(x =&gt;<span style="color: rgba(0, 0, 0, 1)"> x.AddrID);
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 必须要表名</span>
                <span style="background-color: rgba(255, 255, 0, 1)">ob.ToTable(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Stu_Addr</span><span style="color: rgba(128, 0, 0, 1)">"</span></span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)">);</span>
                ob.WithOwner()
                  .HasForeignKey(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">stu_id</span><span style="color: rgba(128, 0, 0, 1)">"</span>).HasConstraintName(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">FK_StuID</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
            });
      });

      modelBuilder.Entity</span>&lt;Teacher&gt;(tet =&gt;<span style="color: rgba(0, 0, 0, 1)">
      {
            tet.HasKey(t </span>=&gt; t.Tid).HasName(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">PK_TeacherID</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>
            tet.OwnsMany(t =&gt; t.Addresses, ob =&gt;<span style="color: rgba(0, 0, 0, 1)">
            {
                ob.HasKey(o </span>=&gt; o.AddrID);   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 主键</span>
                <span style="background-color: rgba(255, 255, 0, 1)">ob.ToTable(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Teacher_Addr</span><span style="color: rgba(128, 0, 0, 1)">"</span>);</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 表名</span>
                ob.WithOwner().HasForeignKey(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">teach_id</span><span style="color: rgba(128, 0, 0, 1)">"</span>).HasConstraintName(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">FK_TeachID</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
            });
      });
    }
}</span></pre>
</div>
<p>这种情况下必须配置 AddressInfo 的表名。</p>
<p>这样数据库会创建四张表:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">CREATE</span> <span style="color: rgba(0, 0, 255, 1)">TABLE</span> <span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Students</span><span style="color: rgba(255, 0, 0, 1)">]</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)">StudentID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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(255, 0, 255, 1)">IDENTITY</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_Stu_id</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">StudentID</span><span style="color: rgba(255, 0, 0, 1)">]</span><span style="color: rgba(0, 0, 0, 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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Teachers</span><span style="color: rgba(255, 0, 0, 1)">]</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)">Tid</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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(255, 0, 255, 1)">IDENTITY</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_TeacherID</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Tid</span><span style="color: rgba(255, 0, 0, 1)">]</span><span style="color: rgba(0, 0, 0, 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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Stu_Addr</span><span style="color: rgba(255, 0, 0, 1)">]</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)">AddrID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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(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)">Province</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">nvarchar</span>(<span style="color: rgba(255, 0, 255, 1)">max</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">City</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">nvarchar</span>(<span style="color: rgba(255, 0, 255, 1)">max</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Town</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">nvarchar</span>(<span style="color: rgba(255, 0, 255, 1)">max</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Road</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">nvarchar</span>(<span style="color: rgba(255, 0, 255, 1)">max</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Street</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">nvarchar</span>(<span style="color: rgba(255, 0, 255, 1)">max</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">ZipCode</span><span style="color: rgba(255, 0, 0, 1)">]</span> <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, 255, 1)">NULL</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)">stu_id</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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, 0, 255, 1)">CONSTRAINT</span> <span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">PK_Stu_Addr</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">AddrID</span><span style="color: rgba(255, 0, 0, 1)">]</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)">FK_StuID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">FOREIGN</span> <span style="color: rgba(0, 0, 255, 1)">KEY</span> <span style="background-color: rgba(255, 255, 0, 1)">(<span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">stu_id</span><span style="color: rgba(255, 0, 0, 1)">]</span>) <span style="color: rgba(0, 0, 255, 1)">REFERENCES</span> <span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Students</span><span style="color: rgba(255, 0, 0, 1)">]</span> (<span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">StudentID</span><span style="color: rgba(255, 0, 0, 1)">]</span>)</span> <span style="color: rgba(0, 0, 255, 1)">ON</span> <span style="color: rgba(0, 0, 255, 1)">DELETE</span> <span style="color: rgba(0, 0, 255, 1)">CASCADE</span><span style="color: rgba(0, 0, 0, 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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Teacher_Addr</span><span style="color: rgba(255, 0, 0, 1)">]</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)">AddrID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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(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)">Province</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">nvarchar</span>(<span style="color: rgba(255, 0, 255, 1)">max</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">City</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">nvarchar</span>(<span style="color: rgba(255, 0, 255, 1)">max</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Town</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">nvarchar</span>(<span style="color: rgba(255, 0, 255, 1)">max</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Road</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">nvarchar</span>(<span style="color: rgba(255, 0, 255, 1)">max</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Street</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">nvarchar</span>(<span style="color: rgba(255, 0, 255, 1)">max</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">ZipCode</span><span style="color: rgba(255, 0, 0, 1)">]</span> <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, 255, 1)">NULL</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)">teach_id</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">int</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, 0, 255, 1)">CONSTRAINT</span> <span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">PK_Teacher_Addr</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(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">AddrID</span><span style="color: rgba(255, 0, 0, 1)">]</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)">FK_TeachID</span><span style="color: rgba(255, 0, 0, 1)">]</span> <span style="color: rgba(0, 0, 255, 1)">FOREIGN</span> <span style="color: rgba(0, 0, 255, 1)">KEY</span> <span style="background-color: rgba(255, 255, 0, 1)">(<span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">teach_id</span><span style="color: rgba(255, 0, 0, 1)">]</span>) <span style="color: rgba(0, 0, 255, 1)">REFERENCES</span> <span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Teachers</span><span style="color: rgba(255, 0, 0, 1)">]</span> (<span style="color: rgba(255, 0, 0, 1)">[</span><span style="color: rgba(255, 0, 0, 1)">Tid</span><span style="color: rgba(255, 0, 0, 1)">]</span>)</span> <span style="color: rgba(0, 0, 255, 1)">ON</span> <span style="color: rgba(0, 0, 255, 1)">DELETE</span> <span style="color: rgba(0, 0, 255, 1)">CASCADE</span><span style="color: rgba(0, 0, 0, 1)">
      );</span></pre>
</div>
<p>&nbsp;</p>
<p>最后,咱们验证一下,Owned 关系是否真的不能共享实例。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">using</span>(MyContext c = <span style="color: rgba(0, 0, 255, 1)">new</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>
    AddressInfo addr1 = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)">()
    {
      Province </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)">,
      City </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)">,
      Town </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)">,
      Road </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)">,
      Street </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">春风街3999号</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
      ZipCode </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">62347</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    };
    AddressInfo addr2 </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)">()
    {
      Province </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)">,
      City </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)">,
      Town </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)">,
      Road </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)">,
      Street </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">送人头街666号</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
      ZipCode </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">833433</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>
    Teacher tt = <span style="color: rgba(0, 0, 255, 1)">new</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>
    Student ss = <span style="color: rgba(0, 0, 255, 1)">new</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>
    tt.Addresses = <span style="color: rgba(0, 0, 255, 1)">new</span> List&lt;AddressInfo&gt;<span style="color: rgba(0, 0, 0, 1)">( );
    ss.Addresses </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> List&lt;AddressInfo&gt;<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, 0, 1)">    c.Students.Add(ss);
    c.Teachers.Add(tt);

    </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)">    c.SaveChanges();
}</span></pre>
</div>
<p>运行后,未抛出异常,但有警告。而且数据库中也有数据。</p>
<p>下面咱们改一下某个地址的 City 属性。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">using</span>(MyContext c2 = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)">())
{
    </span><span style="color: rgba(0, 0, 255, 1)">var</span> r1 =<span style="color: rgba(0, 0, 0, 1)"> c2.Students.ToArray();
    </span><span style="color: rgba(0, 0, 255, 1)">var</span> r2 =<span style="color: rgba(0, 0, 0, 1)"> c2.Teachers.ToArray();
    AddressInfo</span>? addr = r1.First()?.Addresses?<span style="color: rgba(0, 0, 0, 1)">.FirstOrDefault();
    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(addr != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">)
    {
      <strong><span style="background-color: rgba(255, 255, 0, 1)">addr.City </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)">烤鸭市</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>
    }
    c2.SaveChanges();
}</span></pre>
</div>
<p>运行一下。</p>
<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><span style="color: rgba(0, 0, 0, 1)"> Stu_Addr;
</span><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> Teacher_Addr;</pre>
</div>
<p><img src="https://img2024.cnblogs.com/blog/367389/202509/367389-20250913123838971-261014425.png" alt="image" width="660" height="149" loading="lazy"></p>
<p>只有 ID = 1 的学生的第一个地址的 City 属性被更新,而教师地址未更新。可见,两个实体是不共响地址实例的。这很好理解嘛,毕竟是两个表的。</p>
<p>&nbsp;</p>
<p>那么,如果把 Student - AddressInfo,Teacher - AddressInfo 的关系改为普通的一对多关系,又会怎样?</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&lt;Student&gt; Students { <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> DbSet&lt;Teacher&gt; Teachers { <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 ob)
    {
      ……
    }

    </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.Entity</span>&lt;Student&gt;(ste =&gt;<span style="color: rgba(0, 0, 0, 1)">
      {
            ste.HasKey(x </span>=&gt; x.StudentID).HasName(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">PK_Stu_id</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
            
            ste.<span style="background-color: rgba(255, 255, 0, 1)">HasMany(x </span></span><span style="background-color: rgba(255, 255, 0, 1)">=&gt;</span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)"> x.Addresses)</span>
                .WithOne()
                <span style="background-color: rgba(255, 255, 0, 1)">.HasForeignKey(</span></span><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)">stu_id</span><span style="color: rgba(128, 0, 0, 1)">"</span></span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)">)</span>
                .HasConstraintName(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">FK_StuID</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
      });

      modelBuilder.Entity</span>&lt;Teacher&gt;(tet =&gt;<span style="color: rgba(0, 0, 0, 1)">
      {
            tet.HasKey(t </span>=&gt; t.Tid).HasName(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">PK_TeacherID</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
            
            tet.<span style="background-color: rgba(255, 255, 0, 1)">HasMany(f </span></span><span style="background-color: rgba(255, 255, 0, 1)">=&gt;</span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)"> f.Addresses)</span>
                .WithOne()
                <span style="background-color: rgba(255, 255, 0, 1)">.HasForeignKey(</span></span><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)">teacher_id</span><span style="color: rgba(128, 0, 0, 1)">"</span></span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(255, 255, 0, 1)">)</span>
                .HasConstraintName(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">FK_TeacherID</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)"> 注意:这时候 AddressInfo 实体需要主键</span>
      modelBuilder.Entity&lt;AddressInfo&gt;().<span style="background-color: rgba(204, 255, 204, 1)"><strong>HasKey(x =&gt;</strong></span><span style="color: rgba(0, 0, 0, 1)"><span style="background-color: rgba(204, 255, 204, 1)"><strong> x.AddrID)</strong></span>;
    }
}</span></pre>
</div>
<p>改为普通一对多关系时要注意,Student、Teacher、AddressInfo 三个实体都需要主键的, Owned 实体、复合类型(老周以前介绍过)这些不需要主键。</p>
<p>删除刚刚的数据库,重新建立新的数据库,然后写入数据。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">using</span>(MyContext c = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)">())
{
    c.Database.EnsureDeleted();
    c.Database.EnsureCreated();
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 两个地址</span>
    AddressInfo addr1 = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)">()
    {
      Province </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)">,
      City </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)">,
      Town </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)">,
      Road </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)">,
      Street </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">春风街3999号</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
      ZipCode </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">62347</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    };
    AddressInfo addr2 </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)">()
    {
      Province </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)">,
      City </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)">,
      Town </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)">,
      Road </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)">,
      Street </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">送人头街666号</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
      ZipCode </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">833433</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>
    Teacher tt = <span style="color: rgba(0, 0, 255, 1)">new</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>
    Student ss = <span style="color: rgba(0, 0, 255, 1)">new</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>
    tt.Addresses = <span style="color: rgba(0, 0, 255, 1)">new</span> List&lt;AddressInfo&gt;<span style="color: rgba(0, 0, 0, 1)">( );
    ss.Addresses </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> List&lt;AddressInfo&gt;<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, 0, 1)">    c.Students.Add(ss);
    c.Teachers.Add(tt);

    </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)">    c.SaveChanges();
}</span></pre>
</div>
<p>这时候,地址表只有一个,插入的数据如下:</p>
<p><img src="https://img2024.cnblogs.com/blog/367389/202509/367389-20250913161024663-1708369200.png" alt="image" width="625" height="76" loading="lazy"></p>
<p>教师和学生共享一个地址表,分别通过 stu_id 和 teacher_id 外键引用主表记录。</p>
<p>然后更改第一个地址的 City 属性。</p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 0, 255, 1)">using</span>(MyContext c2 = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)">())
{
   </span><span style="color: rgba(0, 0, 255, 1)">var</span> r1 = c2.Students.Include(s =&gt;<span style="color: rgba(0, 0, 0, 1)"> s.Addresses).ToArray();
   </span><span style="color: rgba(0, 0, 255, 1)">var</span> r2 = c2.Teachers.Include(t =&gt;<span style="color: rgba(0, 0, 0, 1)"> t.Addresses).ToArray();
   AddressInfo</span>? addr = r1.First()?.Addresses?<span style="color: rgba(0, 0, 0, 1)">.FirstOrDefault();
   </span><span style="color: rgba(0, 0, 255, 1)">if</span>(addr != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">)
   {
         addr.City </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)">;
   }
   c2.SaveChanges();
}</span></pre>
</div>
<p>地址表的数据变为:</p>
<p><img src="https://img2024.cnblogs.com/blog/367389/202509/367389-20250913161401577-1575272649.png" alt="image" width="485" height="56" loading="lazy"></p>
<p>由于教师和学生共用一个地址表,所以他们的地址信息会相同。</p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 0, 255, 1)">using</span>(MyContext c3 = <span style="color: rgba(0, 0, 255, 1)">new</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> students = c3.Students.Include(x =&gt;<span style="color: rgba(0, 0, 0, 1)"> x.Addresses);
   </span><span style="color: rgba(0, 0, 255, 1)">var</span> teachers = c3.Teachers.Include(x =&gt;<span style="color: rgba(0, 0, 0, 1)"> x.Addresses);

   Console.WriteLine(</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)">);
   </span><span style="color: rgba(0, 0, 255, 1)">foreach</span>(<span style="color: rgba(0, 0, 255, 1)">var</span> s <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> students)
   {
         Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">学生:{s.StudentID}</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)">if</span>(s.Addresses != <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)">foreach</span>(<span style="color: rgba(0, 0, 255, 1)">var</span> a <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> s.Addresses)
             {
               Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\t{a.AddrID}, {a.Province}, {a.City}, {a.Town}</span><span style="color: rgba(128, 0, 0, 1)">"</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)">\n---------- 教师 ---------</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)">foreach</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> t <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> teachers)
   {
         Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">老师:{t.Tid}</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)">if</span> (t.Addresses != <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)">foreach</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> a <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> t.Addresses)
             {
               Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\t{a.AddrID}, {a.Province}, {a.City}, {a.Town}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
             }
         }
   }

}</span></pre>
</div>
<p><img src="https://img2024.cnblogs.com/blog/367389/202509/367389-20250913162604237-1290655132.png" alt="image" width="302" height="160" loading="lazy"></p>
<p>&nbsp;</p>
<p>【总结】</p>
<p>1、Owned 关系中,主实体完全掌控从实体,并且不与其他实体共享数据;</p>
<p>2、被“独占”的实体不用使用 ModelBuilder.Entity&lt;T&gt; 方法配置,因此在 DbContext 派生时,也不能声明为 DbSet&lt;T&gt; 属性。而普通关系中的实体是允许的;</p>
<p>3、Owned 关系有一 Own 一、一 Own 多,不存在 多 Own 多。多 Own 多 就违背“独占”原则了。普通关系中可以有多对多;</p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/tcjiaan/p/19089005
頁: [1]
查看完整版本: 【EF Core】再谈普通实体关系与 Owned 关系的区别