亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Entity?Framework導航屬性介紹

 更新時間:2022年03月09日 09:26:56   作者:.NET開發(fā)菜鳥  
這篇文章介紹了Entity?Framework的導航屬性,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

一、主鍵和外鍵

關系型數據庫中的一條記錄中有若干個屬性,若其中某一個屬性組是能唯一標識一條記錄,該屬性組就可以稱為主鍵。例如:

學生版(學號、姓名、性別、班級)

其中每個學生的學號是唯一的,學號就是一個主鍵。

課程表(課程編號,課程名,學分)

其中課程編號是唯一的,課程編號就是一個主鍵。

成績表(學號、課程號、成績)

成績表中單獨的一個屬性無法唯一標識一條記錄,學號和課程號的組合才能唯一標識一條記錄,所以學號和課程號的屬性組是一個主鍵。

外鍵

成績表中的學號不是成績表的主鍵,但它和學生表中的學號相對應,并且學生表中的學號是學生表的主鍵,則稱成績表中的學號是學生表的外鍵。同理:成績表中的課程號是課程表的外鍵。

EntityFramework中的導航屬性即外鍵。下面通過例子講解如何使用EF的導航屬性。

二、導航屬性

1、新建產品分類表,語句如下:

CREATE table Category
(
  CategoryId int primary key not null identity,
  CategoryName varchar(64)
)

新建產品明細表,其中CategoryId是外鍵

CREATE TABLE [dbo].[ProductDetail](
    [ProductId] [int] IDENTITY(1,1) NOT NULL,
    [ProductName] [varchar](32) NULL,
    [Price] [decimal](9, 2) NULL,
    [CategoryId] [int] NULL,
PRIMARY KEY CLUSTERED
(
    [ProductId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[ProductDetail]  WITH CHECK ADD  CONSTRAINT [FK_Category] FOREIGN KEY([CategoryId])
REFERENCES [dbo].[Category] ([CategoryId])
GO

ALTER TABLE [dbo].[ProductDetail] CHECK CONSTRAINT [FK_Category]
GO

分別往Category表和ProductDetail表中插入一些測試數據:

--Category表插入數據
INSERT INTO Category (CategoryName)
select '電子產品' union
SELECT '家用電器' UNION
SELECT '圖書'

--ProductDetail表插入數據
INSERT INTO ProductDetail (ProductName,Price,CategoryId)
SELECT '蘋果6s手機',5633,1 UNION
SELECT 'Dell電腦',6998,1 UNION
SELECT '佳能相機',5633,1 UNION
SELECT '海爾洗衣機',1234,2 UNION
SELECT '格力空調',2344,2 UNION
SELECT '美的冰箱',3218,2 UNION
SELECT '白鹿原',342,3 UNION
SELECT 'C#高級編程(第十版)',145,3 UNION
SELECT '平凡的世界',231,3

2、使用DataBase First模式生成edmx文件,然后查看Category表和ProductDetail表相對應的實體的定義

Category表定義:

//------------------------------------------------------------------------------
// <auto-generated>
//     此代碼已從模板生成。
//
//     手動更改此文件可能導致應用程序出現意外的行為。
//     如果重新生成代碼,將覆蓋對此文件的手動更改。
// </auto-generated>
//------------------------------------------------------------------------------

namespace EFNavigateDemo
{
    using System;
    using System.Collections.Generic;

    public partial class Category
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public Category()
        {
            this.ProductDetails = new HashSet<ProductDetail>();
        }

        public int CategoryId { get; set; }
        public string CategoryName { get; set; }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<ProductDetail> ProductDetails { get; set; }
    }
}

Category實體類中有一個ProductDetail類型的集合屬性,表示是導航屬性。

實體類型包含其他實體類型(POCO類)的屬性(也可稱為導航屬性),且同時滿足如下條件即可實現延遲加載:

  • 1.該屬性的類型必須為public且不能為Sealed。
  • 2.屬性標記為Virtual。

ProductDetail實體類定義如下:

//------------------------------------------------------------------------------
// <auto-generated>
//     此代碼已從模板生成。
//
//     手動更改此文件可能導致應用程序出現意外的行為。
//     如果重新生成代碼,將覆蓋對此文件的手動更改。
// </auto-generated>
//------------------------------------------------------------------------------

namespace EFNavigateDemo
{
    using System;
    using System.Collections.Generic;

    public partial class ProductDetail
    {
        public int ProductId { get; set; }
        public string ProductName { get; set; }
        public Nullable<decimal> Price { get; set; }
        public Nullable<int> CategoryId { get; set; }

        public virtual Category Category { get; set; }
    }
}

ProductDetail類里面有一個Category類型的屬性。

導航屬性實現延遲加載的四種方式:

1、方式一

using (var dbContext = new CategoryEntities())
{
        dbContext.Configuration.LazyLoadingEnabled = true; // 默認是true,針對導航屬性
         var categoryList = dbContext.Set<Category>().Where(p => p.CategoryId == 3);
         // 只會在數據庫里面查詢Category表,不會查詢ProductDetail表
         foreach(var category in categoryList)
         {
              Console.WriteLine("CategoryId:"+category.CategoryId+ ",CategoryName:"+category.CategoryName);
              // 這時才會去數據庫查詢ProductDetail表
              foreach (var product in category.ProductDetails)
              {
                  Console.WriteLine("ProductName:"+product.ProductName);
              }
          }
}

分別在兩處foreach循環(huán)的地方添加斷點,然后運行程序查看數據庫執(zhí)行的SQL語句情況:

執(zhí)行到斷點1時:

這時查看數據庫監(jiān)控:

繼續(xù)執(zhí)行到斷點2:

這時在查看數據庫監(jiān)控:

會發(fā)現遍歷ProductDetails屬性時也會查詢ProductDetail表。

2、方式二

using (var dbContext = new CategoryEntities())
{
      dbContext.Configuration.LazyLoadingEnabled = false; // 不延遲加載,不會再次查詢了
      var categoryList = dbContext.Set<Category>().Where(p => p.CategoryId == 3);
       // 只會在數據庫里面查詢Category表,不會查詢ProductDetail表
       foreach (var category in categoryList)
       {
            Console.WriteLine("CategoryId:" + category.CategoryId + ",CategoryName:" + category.CategoryName);
            // 這時不會去數據庫查詢了,所以用戶全是空的
            foreach (var product in category.ProductDetails)
            {
               Console.WriteLine("ProductName:" + product.ProductName);
            }
       }
}

這時還是采用和上面一樣的方法加入斷點,只需要查看第二次循環(huán)時的數據庫監(jiān)控情況即可:

從上面的截圖中看出,如果LazyLoadingEnabled設置為false,將不會再查詢ProductDetail表的數據了。

3、方式三

// 顯示加載
using (var dbContext = new CategoryEntities())
{
       // 不延遲加載,指定Include,一次性加載主表和從表的所有數據
       var categoryList = dbContext.Set<Category>().Include("ProductDetails").Where(p => p.CategoryId == 3);
       foreach (var category in categoryList)
       {
            Console.WriteLine("CategoryId:" + category.CategoryId + ",CategoryName:" + category.CategoryName);
            // 不會再查詢
            foreach (var product in category.ProductDetails)
            {
               Console.WriteLine("ProductName:" + product.ProductName);
            }
       }
}

使用Include()方法會一次性加載所有的數據:

4、方式四

在上面的方式2中把LazyLoadingEnabled設置為false以后就不會再查詢ProductDetail表的數據了,這時如果想要查詢ProductDetail表的數據該怎么辦呢?這時可以使用手動加載,代碼如下:

//LoadProperty 手動加載
using (var dbContext = new CategoryEntities())
{
      dbContext.Configuration.LazyLoadingEnabled = false; // 不延遲加載,不會再次查詢了
      var categoryList = dbContext.Set<Category>().Where(p => p.CategoryId == 3);
      foreach (var category in categoryList)
      {
            Console.WriteLine("CategoryId:" + category.CategoryId + ",CategoryName:" + category.CategoryName);
            dbContext.Entry<Category>(category).Collection(p => p.ProductDetails).Load();// 集合顯示加載
             foreach (var product in category.ProductDetails)
             {
                 Console.WriteLine("ProductName:" + product.ProductName);
             }
       }
}

添加斷點:

查看數據庫監(jiān)控:

5、插入數據

對于Category和ProductDetail表如何同時插入數據?先看下面的一段代碼:

using (var dbContext = new CategoryEntities())
{
      using (TransactionScope trans = new TransactionScope())
      {
           Category category = new Category()
           {
                CategoryName = "自行車"
           };
           dbContext.Categories.Add(category);
           dbContext.SaveChanges();//category.CategoryId賦值了
           ProductDetail product = new ProductDetail()
           {
                 ProductName = "美利達",
                 Price = 2312,
                 CategoryId = category.CategoryId
            };

            dbContext.ProductDetails.Add(product);
            dbContext.SaveChanges();
            trans.Complete();//提交事務
      }
}

在第一次SaveChanges()后面的一行代碼加斷點,查看Category信息:

可以看到這是CategoryId已經有值了,查詢數據庫ProductDetail表:

這時Product的信息已經插入到數據庫中了,而且CategordId也是上面生成的CategoryId。

但是這樣會導致一種問題存在:如果第一次SaveChanges()成功,第二次SaveChanges()之前報錯了,但是程序已經不能回滾了,這樣就會導致數據不一致了。使用下面的代碼進行優(yōu)化:

using (var dbContext = new CategoryEntities())
{
      using (TransactionScope trans = new TransactionScope())
      {
           Category category = new Category()
           {
                CategoryName = "汽車"
           };

           ProductDetail product = new ProductDetail()
           {
                 ProductName = "上海大眾",
                 Price = 190090,
                 CategoryId = category.CategoryId
            };

            category.ProductDetails = new List<ProductDetail>() { product};
            dbContext.Categories.Add(category);
            dbContext.SaveChanges();
            trans.Complete();//提交事務
       }
}

經過這樣修改以后可以保證數據的一致性了。這是情況只適合有導航屬性的。

示例代碼下載地址:點此下載

到此這篇關于Entity Framework導航屬性的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • .net Core 使用IHttpClientFactory請求實現

    .net Core 使用IHttpClientFactory請求實現

    這篇文章主要介紹了.net Core 使用IHttpClientFactory請求實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-01-01
  • Asp.Net設計模式之單例模式詳解

    Asp.Net設計模式之單例模式詳解

    這篇文章主要為大家詳細介紹了Asp.Net設計模式之單例模式的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • asp.net中強制取消TFS2008中其它成員的簽出文件的方法

    asp.net中強制取消TFS2008中其它成員的簽出文件的方法

    有個項目,以前的成員離職了,剛好又簽出了一個文件在TFS中并且上了鎖,導致后面的維護無法簽入和生成。在網上查了一下,找到了如下解決辦法
    2012-08-08
  • C# OWC生成圖表

    C# OWC生成圖表

    最近做一個項目,按客戶需求,需要生成一些報表,OWC是比較合適的組件.
    2009-06-06
  • ASP.NET Core 集成 React SPA應用的步驟

    ASP.NET Core 集成 React SPA應用的步驟

    這篇文章主要介紹了ASP.NET Core 集成 React SPA應用的步驟,幫助大家更好的理解和學習使用.net技術,感興趣的朋友可以了解下
    2021-04-04
  • asp.net關于Cookie跨域(域名)的問題

    asp.net關于Cookie跨域(域名)的問題

    Cookie是一個偉大的發(fā)明,它允許Web開發(fā)者保留他們的用戶的登錄狀態(tài)。但是當你的站點有一個以上的域名時就會出現問題了。在Cookie規(guī)范上說,一個cookie只能用于一個域名,不能夠發(fā)給其它的域名。因此,如果在瀏覽器中對一個域名設置了一個cookie,這個cookie對于其它的域名將無效。如果你想讓你的用戶從你的站點中的其中一個進行登錄,同時也可以在其它域名上進行登錄,這可真是一個大難題。
    2012-12-12
  • asp.net窗體的打開和關閉(輸出js)

    asp.net窗體的打開和關閉(輸出js)

    asp.net窗體的打開和關閉(輸出js),需要的朋友可以參考下。
    2011-06-06
  • c#.NET 寫txt文件小例子

    c#.NET 寫txt文件小例子

    在.NET里,有時要往TXT文件里寫內容,其實很簡單。
    2013-06-06
  • .Net?Core?進程守護之Supervisor使用詳解

    .Net?Core?進程守護之Supervisor使用詳解

    這篇文章主要介紹了.Net?Core?進程守護之Supervisor使用,Supervisor它可以很方便的監(jiān)聽、啟動、停止、重啟一個或多個進程,對.Net?Core?進程守護之Supervisor使用相關知識感興趣的朋友一起看看吧
    2022-04-04
  • 集合類List與Dictonary實例練習

    集合類List與Dictonary實例練習

    本文將詳細介紹下List<>泛型集合/Dictonary<>字典/泛型集合練習 /中日期轉換提取為方法以及泛型集合練習之翻譯軟件,感興趣的你可不要錯過了哈
    2013-02-02

最新評論