Entity Framework Core 2.1 Preview 1 新增功能簡介

来源:https://www.cnblogs.com/tdfblog/archive/2018/03/12/entity-framework-core-2-1-preview-1.html
-Advertisement-
Play Games

兩個星期前,微軟發佈了 "EF Core 2.1 Preview 1" ,同時還發佈了 ".NET Core 2.1 Preview 1" 和 "ASP.NET Core 2.1 Preview 1" ;EF Core 2.1 Preview 1 除了 "許多小改進和超過100種產品錯誤修複之外" ...


兩個星期前,微軟發佈了EF Core 2.1 Preview 1,同時還發佈了.NET Core 2.1 Preview 1ASP.NET Core 2.1 Preview 1;EF Core 2.1 Preview 1 除了許多小改進和超過100種產品錯誤修複之外,還包括幾個常用的新功能,今天我為您詳細介紹這些新功能的部分內容。

實體構造函數參數

EF.Core 2.1開始支持在實體的構造函數的實體中轉入參數,目前支持的類型如下:

  • 實體屬性
  • IOC容器中註冊的服務
  • 當前的DbContext
  • 當前實體的元數據

實體屬性

在某些情況下為了保證數據的安全性,將屬性改為只讀,在構造函數中傳遞屬性的值,框架通過參數與屬性匹配關係,將數據行中屬性的值作為參數傳遞給構造函數。

例如下麵的實體:

    public class Order
    {
        public Order(int orderID, string customerID, DateTime? orderDate)
        {
            OrderID = orderID;
            CustomerID = customerID;
            OrderDate = orderDate;
        }

        public int OrderID { get; }
        
        public string CustomerID { get; }

        public DateTime? OrderDate { get; }

    }

其中參數與屬性的配置規則如下:

  • 參數的類型與屬性的類型一致;
  • 屬性名與參數名除首字母不區分大小寫之外,其它字元一致,並且可以使用 _m_做為首碼,使用OrderID屬性來舉例,存在如下匹配規則:

    屬性名 參數名
    OrderID OrderID
    OrderID orderID
    _OrderID orderID
    _OrderID OrderID
    m_OrderID OrderID
    m_OrderID OrderID

具體的匹配規則可以見Github上面的源代碼:https://github.com/aspnet/EntityFrameworkCore/blob/8965f0b91cf89e36abca8636d58420cbd26c22fd/src/EFCore/Metadata/Internal/PropertyParameterBindingFactory.cs#L37-L45
不過我認識後面四種模式有待斟酌的,在.Net開發規範,應該沒有人將公有的屬性名使用 _m_作為首碼。

IOC容器中註冊的服務

在實體的構造函數的中,可以將註冊的服務作為參數。

示例代碼:

    public class Order
    {
        private ILazyLoader _lazyLoader;

        public Order(ILazyLoader lazyLoader)
        {
            this._lazyLoader = lazyLoader;
        }

        public int OrderID { get; set; }
        
        public string CustomerID { get; set; }

        private ICollection<OrderDetail> _orderDetails;

        public ICollection<OrderDetail> OrderDetails
        {
            get => _lazyLoader.Load(this, ref _orderDetails);
            set => _orderDetails = value;
        }
    }

}

其中ILazyLoader是EF Core框架在容器中註冊的一個服務,通過實體的構造函數中傳入,實現導航屬性的賴載入(關於ILazyLoader的具體使用方式在本章的下一節中講解)。

當前的DbContext

在實體的構造函數的參數中,將當前的DbContext作為參數。

示例代碼:

    public class Order
    {
        private NorthwindContext _northwindContext;

        public Order(NorthwindContext northwindContext)
        {
            this._northwindContext = northwindContext;
        }

        public int OrderID { get; set; }
        
        public string CustomerID { get; set; }

        private ICollection<OrderDetail> _orderDetails;

        [NotMapped]
        public ICollection<OrderDetail> OrderDetails
        {
            get
            {
                if (this._orderDetails == null)
                    this._orderDetails = this._northwindContext.Set<OrderDetail>()
                        .Where(item => item.OrderID == this.OrderID).ToList();
                return this._orderDetails;
            }
            set => _orderDetails = value;
        }
    }

當前實體的元數據

在實體的構造函數的參數中,將當前實體的的IEntityType作為參數。

示例代碼:

    public class Order
    {

        private IEntityType _entityType;

        public Order(IEntityType entityType)
        {
            this._entityType = entityType;
        }

        public int OrderID { get; set; }
        
        public string CustomerID { get; set; }

        [NotMapped]
        public IEntityType EntityType
        {
            get { return this._entityType; }
        }

    }

如果實體存在多個構造函數,框架會選擇參數個數最多的那個;如果按參數個數優先選擇後,依然存在多個構造函數,則會拋異常。在當前體驗版本中,暫時無法直接支持自定義參數,不過在下一個發佈版本中,會提供解決方案。

懶載入

懶載入是一個非常有爭論的功能激烈爭論的功能。雖然有些人認為它會導致性能下降或出現意想不到的Bug,但是不影響有些開發人員依舊喜歡它。EF Core 2.1 Preview 1增加了懶載入,提供了兩種實現方式。

使用ILazyLoader介面實現懶載入

在實體的構造函數中傳入ILazyLoader,在導航屬性中,使用介面的Load方法,實現導航屬性的數據載入。

示例代碼:

    public class Order
    {
        private ILazyLoader _lazyLoader;


        public Order(ILazyLoader lazyLoader)
        {
            this._lazyLoader = lazyLoader;
        }

        public int OrderID { get; set; }
        
        public string CustomerID { get; set; }

        public DateTime? OrderDate { get; set; }
   
        private ICollection<OrderDetail> _orderDetails;

        public ICollection<OrderDetail> OrderDetails
        {
            get => this._lazyLoader.Load(this, ref _orderDetails);
            set => _orderDetails = value;
        }
    }

通過代理類實現懶載入

這種方式,需要單獨安裝 Microsoft.EntityFrameworkCore.Proxies Nuget 包,它通過 Castle.Core 框架來生成代理類來實現對導航屬性的延遲載入。

啟用懶載入需要註意以下兩點:

  • 在配置中啟用懶載入;
  • 實體類不能是封閉(sealed)類,導航屬性必須是虛(virtual)屬性。

這種方式,在以前的博客我已經分享過,只不過當時還沒有發佈,原文地址:Entity Framework Core 懶載入

值轉換

EF Core 2.1 允許您將插入資料庫的值自定義轉換邏輯。例如:將屬性的值進行加密與解密。

示例,將插入的值進行Base64編碼,在查詢的時候進行Base64解碼。

定義的UserInfo實體,用於保存用戶信息,屬性PhoneNumber表示用戶的手機號碼;為了用戶信息安全,需要將手機號碼進行加密後再保存到資料庫,只是為了達到演示的目的,我們採用Base64進行編碼。

     public class UserInfo
     {
         public int Id { get; set; }

         public string PhoneNumber { get; set; }
     }

Base64ValueConverter表示進行值轉換的具體邏輯,繼承自泛型ValueConverter<string, string>,具體的邏輯非常簡單,不再敘述。

    public class Base64ValueConverter : ValueConverter<string, string>
    {
        public Base64ValueConverter() : base((v) => ToBase64(v), (v) => FromBase64(v))
        {
        }
        private static string ToBase64(string input)
        {
            if (string.IsNullOrEmpty(input))
                return input;

            var bytes = Encoding.UTF8.GetBytes(input);
            return Convert.ToBase64String(bytes);
        }

        private static string FromBase64(string input)
        {
            if (string.IsNullOrEmpty(input))
                return input;

            var bytes = Convert.FromBase64String(input);
            return Encoding.UTF8.GetString(bytes);
        }
    }

SampleDbContext表示數據上下文,在OnModelCreating方法中,定義UserInfo實體的PhoneNumber屬性需要使用Base64進行值轉換。

    public class SampleDbContext : DbContext
    {

        public DbSet<UserInfo> Users { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            var sqlConnectionStringBuilder = new SqlConnectionStringBuilder
            {
                DataSource = "*******",
                InitialCatalog = "ValueConverterTest",
                UserID = "sa",
                Password = "sa"
            };
            optionsBuilder.UseSqlServer(sqlConnectionStringBuilder.ConnectionString);

            base.OnConfiguring(optionsBuilder);
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<UserInfo>().Property(e => e.PhoneNumber).HasConversion(new Base64ValueConverter());
        }
    }

下麵的代碼是對預期的結果進行單測。

    [Fact]
    public async void ValueConverter_Test()
    {
        string phoneNumber = "13658556925";

        using (SampleDbContext dbContext = new SampleDbContext())
        {
            await dbContext.Database.EnsureDeletedAsync();

            await dbContext.Database.EnsureCreatedAsync();

            dbContext.Users.Add(new UserInfo()
            {
                PhoneNumber = phoneNumber
            });

            await dbContext.SaveChangesAsync();
        }

        UserInfo user;

        using (SampleDbContext dbContext = new SampleDbContext())
        {
            user = dbContext.Users.Single();
        }

        Assert.NotNull(user);
        Assert.Equal(phoneNumber, user.PhoneNumber);
    }

運行後,查詢資料庫中保存的結果:

手機號碼 13658556925 在資料庫保存的值是 MTM2NTg1NTY5MjU=

使用值轉換的另一個常用場景是將枚舉的值存儲為字元串類型,預設情況下,枚舉的值保存到資料庫中是通過整數表示的,如果需要在值存儲為字元串類型。

   public enum CategoryName
   {
       Clothing,
       Footwear,
       Accessories
   }
   public class Category
   {
       public int Id { get; set; }
 
       public CategoryName Name { get; set; }
   }

實體CategoryName屬性是用枚舉表示的,如果在存儲時用字元串類型表示,我們可以在DbContextOnModelCreating方法中使用如下代碼,

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Category>().Property(e => e.Name).HasConversion<string>();
    }

EF Core 預設提供常用類型的轉換,我們只需指定存儲的類型即可,框架預設支持的類型轉換映射表如下:

源類型 目標類型
enum intshortlongsbyteuintushortulongbytedecimaldoublefloat
bool intshortlongsbyteuintushortulongbytedecimaldoublefloat
bool string
bool byte[]
char string
char intshortlongsbyteuintushortulongbytedecimaldoublefloat
char byte[]
Guid byte[]
Guid string
byte[] string
string byte[]
DateTimeDateTimeOffsetTimeSpan stringlongbyte[]
intshortlongsbyteuintushortulongbytedecimaldoublefloat stringbyte[]

LINQ GroupBy 解析

在版本2.1之前,在EF Core中,GroupBy 表達式運算符總是在記憶體中進行計算的。現在支持在大多數情況下將其轉換為SQL GROUP BY子句。

var query = context.Orders
    .GroupBy(o => new { o.CustomerId, o.EmployeeId })
    .Select(g => new
        {
          g.Key.CustomerId,
          g.Key.EmployeeId,
          Sum = g.Sum(o => o.Amount),
          Min = g.Min(o => o.Amount),
          Max = g.Max(o => o.Amount),
          Avg = g.Average(o => Amount)
        });

相應的SQL解析如下所示:

SELECT [o].[CustomerId], [o].[EmployeeId],
    SUM([o].[Amount]), MIN([o].[Amount]), MAX([o].[Amount]), AVG([o].[Amount])
FROM [Orders] AS [o]
GROUP BY [o].[CustomerId], [o].[EmployeeId];

查詢類型

EF Core 模型現在可以包含查詢類型。與實體類型不同,查詢類型沒有定義主鍵,也不能插入、刪除或更新操作(即它們是只讀的),但它們可以直接由查詢返回。查詢類型的一些使用場景:

  • 映射到沒有主鍵的視圖
  • 映射到沒有主鍵的表
  • 映射到模型中定義的查詢
  • 作為FromSql()查詢的返回類型

示例,定義一個簡單的BlogPost模型:

    public class Blog
    {
        public int BlogId { get; set; }
        public string Name { get; set; }
        public string Url { get; set; }
        public ICollection<Post> Posts { get; set; }
    }
    
    public class Post
    {
        public int PostId { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }
        public int BlogId { get; set; }
    }

定義一個簡單的資料庫視圖,能夠查詢每博客與文章數:

    db.Database.ExecuteSqlCommand(
        @"CREATE VIEW View_BlogPostCounts AS 
            SELECT Name, Count(p.PostId) as PostCount from Blogs b
            JOIN Posts p on p.BlogId = b.BlogId
            GROUP BY b.Name");

定義一個類映射的資料庫視圖的結果:

    public class BlogPostsCount
    {
        public string BlogName { get; set; }
        public int PostCount { get; set; }
    }

DbContext類的OnModelCreating使用modelBuilder.Query<T>API。 我們可以使用標準 fluent 配置 Api 來配置查詢類型的映射:

    public class SampleDbContext : DbContext
    {
        public DbQuery<BlogPostsCount> BlogPostCounts { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder
                .Query<BlogPostsCount>().ToTable("View_BlogPostCounts")
                .Property(v => v.BlogName).HasColumnName("Name");
        }
    }

查詢資料庫視圖中的標準方式:

    var postCounts = db.BlogPostCounts.ToList();
    
    foreach (var postCount in postCounts)
    {
        Console.WriteLine($"{postCount.BlogName} has {postCount.PostCount} posts.");
        Console.WriteLine();
    }

最後

EF Core 2.1 Preview1 新增功能的部分內容已經介紹完了,希望對您有幫助。如果文章中描述的功能存在遺漏或錯誤,請在評論中留言,謝謝!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 實現思路 將所需要的數字存入一個列表中 看下圖你就明白了: 實現代碼 快速排序比較冒泡排序效率要高得多~ ...
  • 字元串 字元串或串(String)是由數字、字母、下劃線組成的一串字元,用雙引號或單引號包裹的為字元串 下麵示例: 語法錯誤 第一行出現三個單引號,Python 解析器匹配不上成對的引號,所以報錯。 解決方法:1、可使用雙引號包裹 2、可以使用反斜杠\ 轉義字元 字元串 、數字互轉 內置函數int( ...
  • Python機器學習介紹(Python Machine Learning 中文版) 機器學習,如今最令人振奮的電腦領域之一。看看那些大公司,Google、Facebook、Apple、Amazon早已展開了一場關於機器學習的軍備競賽。從手機上的語音助手、垃圾郵件過濾到逛淘寶時的物品推薦,無一不用... ...
  • Python機器學習 機器學習,如今最令人振奮的電腦領域之一。看看那些大公司,Google、Facebook、Apple、Amazon早已展開了一場關於機器學習的軍備競賽。從手機上的語音助手、垃圾郵件過濾到逛淘寶時的物品推薦,無一不用到機器學習技術。 如果你對機器學習感興趣,甚至是想從事相關職業... ...
  • 一、前言 JUC這部分還有線程池這一塊沒有分析,需要抓緊時間分析,下麵開始ThreadPoolExecutor,其是線程池的基礎,分析完了這個類會簡化之後的分析,線程池可以解決兩個不同問題:由於減少了每個任務調用的開銷,它們通常可以在執行大量非同步任務時提供增強的性能,並且還可以提供綁定和管理資源(包 ...
  • 內容:Java變數,基本數據類型 邏輯類型:boolean =true/false整數類型:byte占一個位元組,short占兩個位元組,int占四個位元組,long占8個位元組 int 可以表達十進位範圍 (2147483648,4294967296)字元類型:char占兩個位元組 (加單引號)ch=97, ...
  • 前言 在一個小項目的需求中,我需要一個短鏈生成伺服器來縮短一些某個網站的鏈接。 剛開始我使用的是新浪的短鏈生成服務,後來心血來潮Google了一下短鏈生成的演算法,在知乎上看到了 "一個非常棒的構思" ,也就是直接使用資料庫的id的62進位形式作為短鏈索引。 當天我們就把新浪的短鏈換成了自己的服務,不 ...
  • 作為一個java的學習者,我相信JDBC是大家最早接觸也是入門級別的資料庫連接方式,所以我們先來回憶一下JDBC作為一種用於執行SQL語句的Java API是如何工作的。下麵的一段代碼就是最基本的JDBC開發流程。 在上代碼之前要先導入JDBC的jar包,由於我用的資料庫是mysql,所以要先導 入 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...