<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      【EF Core】再談普通實體關系與 Owned 關系的區別

      在很多個世紀前,老周曾寫過實體之間普通關系(一對一,一對多,多對多)與 Owned 關系的區別。不過,那次寫得比較粗淺,逼格不夠高,于是,老周厚著臉皮地決定重新寫一下。

      首先,為什么這次老周用原單詞 Owned 呢,官方文檔目前的翻譯(懷疑是機器干的)為“從屬”,這種說法與普通關系數據庫中一對多、多對多等關系描述不太 好區分。其實老周覺得應該把 Owned 翻譯為“獨占”關系——你完全屬于我的。普通關系中的廁所是公共廁所,我可以用,鄰居A、B、C也可以用;而 Owned 關系中的廁所是私人的,我用我家的廁所,A用A家自己的廁所,B不能用A家的廁所。

      這種玩意兒比某少年馬戲團的粉絲還抽象,要理解最好的方法是比較。本文老周就對這兩類關系做一輪大比拼。

      One and One

      首先我們來看“一”和“一”的方式。為了保持數據結構的一致,咱們用這三個實體來實驗。

      public class HardwareInfo
      {
          public int HwID { get; set; }               // 主鍵
          public long MemorySize { get; set; }        // 內存大小
          public int HarddiskNum { get; set; }        // 硬盤數量
          public long HDDSize { get; set; }           // 硬盤大小
          public bool InteGrp { get; set; }           // 是否有集顯
      }
      
      public class Desktop
      {
          public int ID { get; set; }                 // 主鍵
          public HardwareInfo HWInfo { get; set; }    // 硬件信息
      }
      
      public class Laptop
      {
          public int ID { get; set; }                  // 主鍵
          public HardwareInfo HWInfo { get; set; }     // 硬件信息
      }

      HardwareInfo 表示硬件參數,不管是臺式機(Desktop)還是筆記本(Laptop)都可以共用這樣的數據結構。

      先定義用在普通關系的上下文類——MyContextR,R結尾表示 Relational。

      public class MyContextR : DbContext
      {
          public DbSet<Desktop> PCs { get; set; }
          public DbSet<Laptop> Laps { get; set; }
      
          protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
          {
              optionsBuilder.UseSqlServer(@"server=<你的服務器>;database=rdb")
              .LogTo(m => Debug.WriteLine(m));
          }
      
          protected override void OnModelCreating(ModelBuilder mb)
          {
              // 配置主鍵
              mb.Entity<HardwareInfo>().HasKey(m => m.HwID);
      
              mb.Entity<Laptop>(ent =>
              {
                  ent.HasKey(k => k.ID);
                  ent.HasOne(x => x.HWInfo);
              });
              mb.Entity<Desktop>(eb =>
              {
                  eb.HasKey(a => a.ID);
                  eb.HasOne(y => y.HWInfo);
              });
          }
      }

      由于老周在定義實體類時“粗心大意”,主鍵屬性的命名無法讓 EF Core 自動識別,所以要在 OnModelCreating 方法中顯式配置一下。注意,HasOne 讓它們建立一對一的關系,即PC有一個HardwareInfo 實例,筆記本也有。

      第二個上下文類是面向“獨占”關系的 MyContextO,O 結尾表示 Owned。

      public class MyContextO : DbContext
      {
          public DbSet<Laptop> Laps { get; set; }
          public DbSet<Desktop> PCs { get; set; }
      
          protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
          {
              optionsBuilder.UseSqlServer(@"server=<你的服務器>;database=odb")
              .LogTo(g => Debug.WriteLine(g));
          }
      
          protected override void OnModelCreating(ModelBuilder mb)
          {
              mb.Entity<Laptop>().HasKey(m => m.ID);
              mb.Entity<Desktop>().HasKey(n => n.ID);
              mb.Entity<Laptop>().OwnsOne(x => x.HWInfo);
              mb.Entity<Desktop>().OwnsOne(w => w.HWInfo);
          }
      }

      OwnsOne 表示一占一,PC占用一個HardwareInfo實例,筆記本也占用一個,兩者不相干。這種情形 HardwareInfo 是不需要主鍵的,為什么?往下看你就懂了。

      咱們依次實例化這兩個上下文對象,然后讓它自己創建數據庫。

      static void Main(string[] args)
      {
          using MyContextR c1 = new();
          c1.Database.EnsureCreated();
      
          using MyContextO c2 = new();
          c2.Database.EnsureCreated();
      }

      實驗結果發現,普通一對一關系中,創建了三個表:

      CREATE TABLE [HardwareInfo] (
          [HwID] int NOT NULL IDENTITY,
          [MemorySize] bigint NOT NULL,
          [HarddiskNum] int NOT NULL,
          [HDDSize] bigint NOT NULL,
          [InteGrp] bit NOT NULL,
          CONSTRAINT [PK_HardwareInfo] PRIMARY KEY ([HwID]);
      
      CREATE TABLE [Laps] (
          [ID] int NOT NULL IDENTITY,
          [HWInfoHwID] int NULL,
          CONSTRAINT [PK_Laps] PRIMARY KEY ([ID]),
          CONSTRAINT [FK_Laps_HardwareInfo_HWInfoHwID] FOREIGN KEY ([HWInfoHwID]) REFERENCES [HardwareInfo] ([HwID])
      );
      
      CREATE TABLE [PCs] (
          [ID] int NOT NULL IDENTITY,
          [HWInfoHwID] int NULL,
          CONSTRAINT [PK_PCs] PRIMARY KEY ([ID]),
          CONSTRAINT [FK_PCs_HardwareInfo_HWInfoHwID] FOREIGN KEY ([HWInfoHwID]) REFERENCES [HardwareInfo] ([HwID])
      );

      EF Core 這貨還挺聰明的,把外鍵分別放在 Desktop 和 Laptop 中,這樣可避免在 HardwareInfo 中出現兩個外鍵,不好約束。畢竟這是一對一關系,外鍵放在哪一端都可以。

      然后看看“獨占”關系中的一對一,它創建了兩個表:

      CREATE TABLE [Laps] (
          [ID] int NOT NULL IDENTITY,
          [HWInfo_HwID] int NULL,
          [HWInfo_MemorySize] bigint NULL,
          [HWInfo_HarddiskNum] int NULL,
          [HWInfo_HDDSize] bigint NULL,
          [HWInfo_InteGrp] bit NULL,
          CONSTRAINT [PK_Laps] PRIMARY KEY ([ID])
      );
      
      CREATE TABLE [PCs] (
          [ID] int NOT NULL IDENTITY,
          [HWInfo_HwID] int NULL,
          [HWInfo_MemorySize] bigint NULL,
          [HWInfo_HarddiskNum] int NULL,
          [HWInfo_HDDSize] bigint NULL,
          [HWInfo_InteGrp] bit NULL,
          CONSTRAINT [PK_PCs] PRIMARY KEY ([ID])
      );

      你沒看錯,只有兩個表,HardwareInfo 直接被拆開了,Desktop和Laptop各擁有一份。現在你明白了吧,為什么 HardwareInfo 在這種關系下不需要主鍵,因為它們不獨成表。

      那么,如果讓 HardwareInfo 獨立建表呢,又會怎樣?咱們把 MyContextO 類的代碼改一下,為 HardwareInfo 類單獨建表。

      public class MyContextO : DbContext
      {
          public DbSet<Laptop> Laps { get; set; }
          public DbSet<Desktop> PCs { get; set; }
      
          ……
      
          protected override void OnModelCreating(ModelBuilder mb)
          {
              mb.Entity<Desktop>(et =>
              {
                  et.HasKey(a => a.ID);
                  et.OwnsOne(b => b.HWInfo, ob =>
                  {
                      ob.ToTable("Desktop_HW");
                      ob.WithOwner();
                  });
              });
              mb.Entity<Laptop>(et =>
              {
                  et.HasKey(a => a.ID);
                  et.OwnsOne(m => m.HWInfo, ob =>
                  {
                      ob.ToTable("Laptop_HW");
                      ob.WithOwner();
                  });
              });
          }
      }

      這個地方,WithOwner 方法可以不調用,因為 HardwareInfo 類沒有定義指向 Laptop 或 Desktop 的反向導航屬性。

      這一次,會創建四個表:

      CREATE TABLE [Desktop_HW] (
          [DesktopID] int NOT NULL,
          [HwID] int NOT NULL,
          [MemorySize] bigint NOT NULL,
          [HarddiskNum] int NOT NULL,
          [HDDSize] bigint NOT NULL,
          [InteGrp] bit NOT NULL,
          CONSTRAINT [PK_Desktop_HW] PRIMARY KEY ([DesktopID]),
          CONSTRAINT [FK_Desktop_HW_PCs_DesktopID] FOREIGN KEY ([DesktopID]) REFERENCES [PCs] ([ID]) ON DELETE CASCADE
      );
      
      CREATE TABLE [Laptop_HW] (
          [LaptopID] int NOT NULL,
          [HwID] int NOT NULL,
          [MemorySize] bigint NOT NULL,
          [HarddiskNum] int NOT NULL,
          [HDDSize] bigint NOT NULL,
          [InteGrp] bit NOT NULL,
          CONSTRAINT [PK_Laptop_HW] PRIMARY KEY ([LaptopID]),
          CONSTRAINT [FK_Laptop_HW_Laps_LaptopID] FOREIGN KEY ([LaptopID]) REFERENCES [Laps] ([ID]) ON DELETE CASCADE
      );
      
      CREATE TABLE [PCs] (
          [ID] int NOT NULL IDENTITY,
          CONSTRAINT [PK_PCs] PRIMARY KEY ([ID])
      );
      
      CREATE TABLE [Laps] (
          [ID] int NOT NULL IDENTITY,
          CONSTRAINT [PK_Laps] PRIMARY KEY ([ID])
      );

      EF Core 很有才,咱們沒有為 HardwareInfo 定義主鍵,于是它自己生成了,在 Laptop_HW 表中生成 LaptopID 列作為主鍵,同時也作為外鍵,引用 Laptop.ID;在 Desktop_HW 表中生成了 DesktopID 列作為主鍵,同時作為外鍵,引用 Desktop.ID。

      還要補充解釋一下模型配置代碼。

       mb.Entity<Laptop>(et =>
       {
           et.HasKey(a => a.ID);
           et.OwnsOne(m => m.HWInfo, ob =>
           {
               ob.ToTable("Laptop_HW");
               //ob.WithOwner();
           });
       });

      ToTable 的調用在此處是必須的,否則按默認約定,它會使用表名 Laps,即和 Laptop 保持一致,這會導致出錯。而且,Laptop 和 Desktop 不能共享一個 HardwareInfo 實體。這樣配置也會報錯:

      protected override void OnModelCreating(ModelBuilder mb)
      {
          mb.Entity<Desktop>(et =>
          {
              et.HasKey(a => a.ID);
              et.OwnsOne(b => b.HWInfo, ob =>
              {
                  ob.ToTable("HW_info");
              });
          });
          mb.Entity<Laptop>(et =>
          {
              et.HasKey(a => a.ID);
              et.OwnsOne(m => m.HWInfo, ob =>
              {
                  ob.ToTable("HW_info");
              });
          });
      }

      這就等于 Desktop 和 Laptop 同時占有相同的 HardwareInfo 實例,運行時也會報錯。

       

      One and Many

       這里咱們已經沒有必要再與普通的一對多關系對比了,上面的對比已經明確 Owned 關系是獨占性的,不共享實例。下面咱們看看實體獨占多個實例的情況。這種情況下,被占有的對象不會與主對象共用一個表了——拆分的列無法表示多個實例。

      舉個例子。

      public class AddressInfo
      {
          /// <summary>
          /// 這里有主鍵
          /// </summary>
          public int AddrID {  get; set; }
          /// <summary>
          ////// </summary>
          public string Province { get; set; } = "";
          /// <summary>
          ////// </summary>
          public string City { get; set; } = "";
          /// <summary>
          ////// </summary>
          public string Town { get; set; } = "";
          /// <summary>
          ////// </summary>
          public string Road { get; set; } = "";
          /// <summary>
          /// 街道
          /// </summary>
          public string Street { get; set; } = "";
          /// <summary>
          /// 郵編
          /// </summary>
          public string? ZipCode { get; set; }
      }
      
      public class Student
      {
          public int StudentID { get; set; }
          public IList<AddressInfo>? Addresses { get; set; }
      }

      如果這里的地址表示收貨地址,于是每個學生都可以擁有多個地址。

      然后,上下文類是這樣的。

      public class MyContext : DbContext
      {
          public DbSet<Student> Students { get; set; }
      
          protected override void OnConfiguring(DbContextOptionsBuilder ob)
          {
              SqlConnectionStringBuilder strbd = new();
              strbd.DataSource = <你的服務器>;
              strbd.InitialCatalog = "TestDB";
              ob.UseSqlServer(strbd.ConnectionString)
                  .LogTo(x => Console.WriteLine(x));
          }
      
          protected override void OnModelCreating(ModelBuilder modelBuilder)
          {
              modelBuilder.Entity<Student>(ste =>
              {
                  ste.HasKey(x => x.StudentID).HasName("PK_Stu_id");
                  // 它占有多個 Addr
                  ste.OwnsMany(k => k.Addresses, ob =>
                  {
                      // 此處可以配置主鍵
                      ob.HasKey(x => x.AddrID);
                      ob.WithOwner()
                          .HasForeignKey("stu_id").HasConstraintName("FK_StuID");
                  });
              });
          }
      }

      數據庫會創建兩張表:

      CREATE TABLE [Students] (
                [StudentID] int NOT NULL IDENTITY,
                CONSTRAINT [PK_Stu_id] PRIMARY KEY ([StudentID])
            );
      
      CREATE TABLE [AddressInfo] (
                [AddrID] int NOT NULL IDENTITY,
                [Province] nvarchar(max) NOT NULL,
                [City] nvarchar(max) NOT NULL,
                [Town] nvarchar(max) NOT NULL,
                [Road] nvarchar(max) NOT NULL,
                [Street] nvarchar(max) NOT NULL,
                [ZipCode] nvarchar(max) NULL,
                [stu_id] int NOT NULL,
                CONSTRAINT [PK_AddressInfo] PRIMARY KEY ([AddrID]),
                CONSTRAINT [FK_StuID] FOREIGN KEY ([stu_id]) REFERENCES [Students] ([StudentID]) ON DELETE CASCADE
            );

      AddressInfo 表會創建一個外鍵來引用 Students 表的主鍵列。

      接著,咱們加一個 Teacher 實體,和學生一樣,老師也有多個收貨地址。

      public class Teacher
      {
          public int Tid { get; set; }
          public IList<AddressInfo>? Addresses { get; set; }
      }

      上下文類也要做相應修改。

      public class MyContext : DbContext
      {
          public DbSet<Student> Students { get; set; }
          public DbSet<Teacher> Teachers { get; set; }
      
         ……
      
          protected override void OnModelCreating(ModelBuilder modelBuilder)
          {
              modelBuilder.Entity<Student>(ste =>
              {
                  ste.HasKey(x => x.StudentID).HasName("PK_Stu_id");
                  // 它占有多個 Addr
                  ste.OwnsMany(k => k.Addresses, ob =>
                  {
                      // 此處可以配置主鍵
                      ob.HasKey(x => x.AddrID);
                      // 必須要表名
                      ob.ToTable("Stu_Addr");
                      ob.WithOwner()
                          .HasForeignKey("stu_id").HasConstraintName("FK_StuID");
                  });
              });
      
              modelBuilder.Entity<Teacher>(tet =>
              {
                  tet.HasKey(t => t.Tid).HasName("PK_TeacherID");
                  // 占用多個地址
                  tet.OwnsMany(t => t.Addresses, ob =>
                  {
                      ob.HasKey(o => o.AddrID);   // 主鍵
                      ob.ToTable("Teacher_Addr"); // 表名
                      ob.WithOwner().HasForeignKey("teach_id").HasConstraintName("FK_TeachID");
                  });
              });
          }
      }

      這種情況下必須配置 AddressInfo 的表名。

      這樣數據庫會創建四張表:

      CREATE TABLE [Students] (
                [StudentID] int NOT NULL IDENTITY,
                CONSTRAINT [PK_Stu_id] PRIMARY KEY ([StudentID])
            );
      
      CREATE TABLE [Teachers] (
                [Tid] int NOT NULL IDENTITY,
                CONSTRAINT [PK_TeacherID] PRIMARY KEY ([Tid])
            );
      
      CREATE TABLE [Stu_Addr] (
                [AddrID] int NOT NULL IDENTITY,
                [Province] nvarchar(max) NOT NULL,
                [City] nvarchar(max) NOT NULL,
                [Town] nvarchar(max) NOT NULL,
                [Road] nvarchar(max) NOT NULL,
                [Street] nvarchar(max) NOT NULL,
                [ZipCode] nvarchar(max) NULL,
                [stu_id] int NOT NULL,
                CONSTRAINT [PK_Stu_Addr] PRIMARY KEY ([AddrID]),
                CONSTRAINT [FK_StuID] FOREIGN KEY ([stu_id]) REFERENCES [Students] ([StudentID]) ON DELETE CASCADE
            );
      
      CREATE TABLE [Teacher_Addr] (
                [AddrID] int NOT NULL IDENTITY,
                [Province] nvarchar(max) NOT NULL,
                [City] nvarchar(max) NOT NULL,
                [Town] nvarchar(max) NOT NULL,
                [Road] nvarchar(max) NOT NULL,
                [Street] nvarchar(max) NOT NULL,
                [ZipCode] nvarchar(max) NULL,
                [teach_id] int NOT NULL,
                CONSTRAINT [PK_Teacher_Addr] PRIMARY KEY ([AddrID]),
                CONSTRAINT [FK_TeachID] FOREIGN KEY ([teach_id]) REFERENCES [Teachers] ([Tid]) ON DELETE CASCADE
            );

       

      最后,咱們驗證一下,Owned 關系是否真的不能共享實例。

      using(MyContext c = new())
      {
          // 四個地址
          AddressInfo addr1 = new()
          {
              Province = "冬瓜省",
              City = "嘎子市",
              Town = "小連子鎮",
              Road = "牛逼路",
              Street = "春風街3999號",
              ZipCode = "62347"
          };
          AddressInfo addr2 = new()
          {
              Province = "提頭省",
              City = "抬扛臺",
              Town = "煙斗鎮",
              Road = "王八路",
              Street = "送人頭街666號",
              ZipCode = "833433"
          };
      
          // 教師實例
          Teacher tt = new();
          // 學生實例
          Student ss = new();
          // 讓他們使用相同的地址實例
          tt.Addresses = new List<AddressInfo>( [addr1, addr2] );
          ss.Addresses = new List<AddressInfo>( [addr1, addr2] );
      
          // 添加實體
          c.Students.Add(ss);
          c.Teachers.Add(tt);
      
          // 保存到數據庫
          c.SaveChanges();
      }

      運行后,未拋出異常,但有警告。而且數據庫中也有數據。

      下面咱們改一下某個地址的 City 屬性。

      using(MyContext c2 = new())
      {
          var r1 = c2.Students.ToArray();
          var r2 = c2.Teachers.ToArray();
          AddressInfo? addr = r1.First()?.Addresses?.FirstOrDefault();
          if(addr != null)
          {
              addr.City = "烤鴨市";
          }
          c2.SaveChanges();
      }

      運行一下。

      然后咱們查詢一下兩個地址表的數據。

      select * from Stu_Addr;
      select * from Teacher_Addr;

      image

      只有 ID = 1 的學生的第一個地址的 City 屬性被更新,而教師地址未更新。可見,兩個實體是不共響地址實例的。這很好理解嘛,畢竟是兩個表的。

       

      那么,如果把 Student - AddressInfo,Teacher - AddressInfo 的關系改為普通的一對多關系,又會怎樣?

      public class MyContext : DbContext
      {
          public DbSet<Student> Students { get; set; }
          public DbSet<Teacher> Teachers { get; set; }
      
          protected override void OnConfiguring(DbContextOptionsBuilder ob)
          {
              ……
          }
      
          protected override void OnModelCreating(ModelBuilder modelBuilder)
          {
              modelBuilder.Entity<Student>(ste =>
              {
                  ste.HasKey(x => x.StudentID).HasName("PK_Stu_id");
                  
                  ste.HasMany(x => x.Addresses)
                      .WithOne()
                      .HasForeignKey("stu_id")
                      .HasConstraintName("FK_StuID");
              });
      
              modelBuilder.Entity<Teacher>(tet =>
              {
                  tet.HasKey(t => t.Tid).HasName("PK_TeacherID");
                  
                  tet.HasMany(f => f.Addresses)
                      .WithOne()
                      .HasForeignKey("teacher_id")
                      .HasConstraintName("FK_TeacherID");
              });
      
              // 注意:這時候 AddressInfo 實體需要主鍵
              modelBuilder.Entity<AddressInfo>().HasKey(x => x.AddrID);
          }
      }

      改為普通一對多關系時要注意,Student、Teacher、AddressInfo 三個實體都需要主鍵的, Owned 實體、復合類型(老周以前介紹過)這些不需要主鍵。

      刪除剛剛的數據庫,重新建立新的數據庫,然后寫入數據。

      using(MyContext c = new())
      {
          c.Database.EnsureDeleted();
          c.Database.EnsureCreated();
          // 兩個地址
          AddressInfo addr1 = new()
          {
              Province = "冬瓜省",
              City = "嘎子市",
              Town = "小連子鎮",
              Road = "牛逼路",
              Street = "春風街3999號",
              ZipCode = "62347"
          };
          AddressInfo addr2 = new()
          {
              Province = "提頭省",
              City = "抬扛臺",
              Town = "煙斗鎮",
              Road = "王八路",
              Street = "送人頭街666號",
              ZipCode = "833433"
          };
      
          // 教師實例
          Teacher tt = new();
          // 學生實例
          Student ss = new();
          // 讓他們使用相同的地址實例
          tt.Addresses = new List<AddressInfo>( [addr1, addr2] );
          ss.Addresses = new List<AddressInfo>( [addr1, addr2] );
      
          // 添加實體
          c.Students.Add(ss);
          c.Teachers.Add(tt);
      
          // 保存到數據庫
          c.SaveChanges();
      }

      這時候,地址表只有一個,插入的數據如下:

      image

      教師和學生共享一個地址表,分別通過 stu_id 和 teacher_id 外鍵引用主表記錄。

      然后更改第一個地址的 City 屬性。

       using(MyContext c2 = new())
       {
           var r1 = c2.Students.Include(s => s.Addresses).ToArray();
           var r2 = c2.Teachers.Include(t => t.Addresses).ToArray();
           AddressInfo? addr = r1.First()?.Addresses?.FirstOrDefault();
           if(addr != null)
           {
               addr.City = "烤鴨市";
           }
           c2.SaveChanges();
       }

      地址表的數據變為:

      image

      由于教師和學生共用一個地址表,所以他們的地址信息會相同。

       using(MyContext c3 = new())
       {
           // 加載全部數據
           var students = c3.Students.Include(x => x.Addresses);
           var teachers = c3.Teachers.Include(x => x.Addresses);
      
           Console.WriteLine("---------- 學生 ---------");
           foreach(var s in students)
           {
               Console.WriteLine($"學生:{s.StudentID}");
               if(s.Addresses != null)
               {
                   foreach(var a in s.Addresses)
                   {
                       Console.WriteLine($"\t{a.AddrID}, {a.Province}, {a.City}, {a.Town}");
                   }
               }
           }
           
           Console.WriteLine("\n---------- 教師 ---------");
           foreach (var t in teachers)
           {
               Console.WriteLine($"老師:{t.Tid}");
               if (t.Addresses != null)
               {
                   foreach (var a in t.Addresses)
                   {
                       Console.WriteLine($"\t{a.AddrID}, {a.Province}, {a.City}, {a.Town}");
                   }
               }
           }
      
       }

      image

       

      【總結】

      1、Owned 關系中,主實體完全掌控從實體,并且不與其他實體共享數據;

      2、被“獨占”的實體不用使用 ModelBuilder.Entity<T> 方法配置,因此在 DbContext 派生時,也不能聲明為 DbSet<T> 屬性。而普通關系中的實體是允許的;

      3、Owned 關系有一 Own 一、一 Own 多,不存在 多 Own 多。多 Own 多 就違背“獨占”原則了。普通關系中可以有多對多;

       

      posted @ 2025-09-13 16:32  東邪獨孤  閱讀(1555)  評論(2)    收藏  舉報
      主站蜘蛛池模板: 久久人妻无码一区二区三区av| 亚洲天堂一区二区三区四区| 太深太粗太爽太猛了视频| 徐州市| 亚洲国产激情一区二区三区| 国产不卡一区二区四区| 国产一区二区一卡二卡| 小嫩批日出水无码视频免费| 国产L精品国产亚洲区在线观看| 国产高颜值不卡一区二区 | 国产69精品久久久久人妻| 亚洲最大福利视频网| 国内精品自产拍在线播放| 高清破外女出血AV毛片| 胸大美女又黄的网站| 日本韩国日韩少妇熟女少妇| 亚洲另类丝袜综合网| 人妻体内射精一区二区三区| 欧美怡春院一区二区三区| 最新的国产成人精品2020| 无码专区—va亚洲v天堂麻豆| 国产91成人亚洲综合在线| 四虎国产精品永久在线| 疯狂做受XXXX高潮国产| 亚洲人成网站在线在线观看| 久久久久国产精品人妻| 亚洲区中文字幕日韩精品| 湖南省| 少妇人妻偷人偷人精品| 国产午夜精品无码一区二区| 免费激情网址| 久久88香港三级台湾三级播放| 精品无码一区二区三区在线| 成人啪精品视频网站午夜| 亚洲全网成人资源在线观看| 最新国产精品拍自在线播放| 佛学| 91亚洲国产三上悠亚在线播放| 精品999日本久久久影院| 日韩国产中文字幕精品| 日本一区二区久久人妻高清|