2020年10月21日 星期三

Entity Framework Core EF Core 的 紀錄修改

 

Entity Framework Core EF Core 的 紀錄修改

在上一篇 EF Core 討論文章 EF Core 的 紀錄新增 ,說明了如何使用 EF Core 來建立產生一筆新的資料庫紀錄的做法。

在這篇文章中,來了解如何使用 EF Core 來進行記錄修改動作的作法,關於更多這方面的應用,可以參考 基本儲存 這份文件內容。

請按照底下的步驟來進行操作

建立練習專案

  • 打開 Visual Studio 2019

  • 點選 [建立新的專案] 按鈕

  • 在 [建立新專案] 對話窗內,選擇 [Blazor 應用程式] 專案樣板

  • 在 [設定新的專案] 對話窗內,於 [專案名稱] 欄位內輸入 efUpdateRecord

  • 在 [建立新的 Blazor 應用程式] 對話窗內,選擇 [Blazor 伺服器應用程式] 這個選項

    在該對話窗右半部的其他選項,可以不用變更

  • 點選 [建立] 按鈕,以便開始建立這個專案

加入 Entity Framework Core 要使用到的 NuGet 套件

  • 滑鼠右擊專案內的 [相依性] 節點
  • 選擇 [管理 NuGet 套件]
  • 點選 [瀏覽] 標籤分頁頁次
  • 在 [搜尋] 文字輸入盒內,輸入 [Microsoft.EntityFrameworkCore.SqlServer]
  • 點選 [安裝] 按鈕以便安裝這個套件
  • 在 [搜尋] 文字輸入盒內,輸入 [Microsoft.EntityFrameworkCore.Tools]
  • 點選 [安裝] 按鈕以便安裝這個套件

使用反向工程來產生 Entity Framework 要用到的 Entity 模型相關類別

  • 切換到 [套件管理器主控台] 視窗

    若沒有看到 [套件管理器主控台] 視窗,點選功能表 [工具] > [NuGet 套件管理員] > [套件管理器主控台]

  • 在 [套件管理器主控台] 輸入底下內容

    因為都在同一個專案內,所以,這裡可以省略 StartupProject & Project 這兩個參數,因此,底下的指令會更為精簡

Scaffold-DbContext "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=School" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -f

請打開這個 [Program.cs] 檔案,完成底下的程式碼

var context = new DataContext();
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
 
Department department1 = new Department() { Name = "新增的科系1", };
context.Department.Add(department1);
context.SaveChanges();
Department department2 = context.Department.First();
department2.Name = "修改該科系名稱";
context.SaveChanges();
Reset(context); // 清除 ChangeTracker 內的科系紀錄
Department department3 = new Department()
{
    Id = department1.Id,
    Name = "使用狀態來修改的科系名稱",
};
context.Entry(department3).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
context.SaveChanges();
foreach (var item in context.Department.ToList())
{
    Console.WriteLine($"科系名稱:{item.Name}");
}

public static void Reset(DataContext context)
{
    #region 解除快取紀錄
    foreach (var item in context
        .Set<Department>().Local.ToList())
    {
        context.Entry(item).State = 
            Microsoft.EntityFrameworkCore.EntityState.Detached;
    }
    #endregion
}

上面的程式碼使用 new 運算子來建立 Department 類別的物件,也就是科系名稱為 [新增的科系1] 的紀錄,並且呼叫了 SaveChanges 告知 Entity Framework Core 將這筆紀錄新增到資料庫,不過,記得要呼叫 context.SaveChanges() 方法,這樣的異動請求才會更新到資料庫內;接著,使用了 context.Department.First() 表示式,取得科系資料表內的第一筆紀錄,也就是剛剛建立的紀錄。

現在要來變更剛剛取得的紀錄,也就是 department2 這個物件,使用這樣的敘述 department2.Name = "修改該科系名稱"; ,當想要同步這個 .NET 物件與資料庫內的紀錄時候,還是一樣要使用 呼叫 context.SaveChanges() 方法,因為 Entity Framework Core 發現到在變更追蹤內的紀錄,與剛剛修改的物件不相同,因此,將會產生出 Update 的 SQL 敘述,並且把這個敘述送到資料庫內。

由於在取得科系資料表內的第一筆紀錄的時候,使用了 Department department2 = context.Department.First(); 這樣的敘述,因此,在 Entity Framework Core 內的變更追蹤內,將會有剛剛取得的紀錄物件,現在將會呼叫一個客製方法 Reset(context),這個方法將會清除 ChangeTracker 內的有關科系紀錄,這樣在 Entity Framework Core 內的變更追蹤系統內,就都沒有任何有關科系資料表相關的最新紀錄了。

在這裡使用 C# new 運算子,建立一個 department3 的物件

接下來,將使用 C# new 運算子,建立一個 department3 .NET 物件,不過,該物件的 Id 屬性值將會與 department1的物件值相同,不過科系名稱欄位卻是不同的內容,由於由於 Entity Framework Core 內的變更追蹤系統內,沒有任何有關科系資料表相關的最新紀錄,因此,當下達 context.SaveChanges() 方法,這個物件的異動,是不會同步到資料庫內,因此,需要使用下面兩種做法的其中一個。

第一個做法是下達 context.Department.Update(department3); 這樣的敘述,如同前一篇文章要新增一筆紀錄相同,只不過這裡要呼叫的 Update 這樣的方法;第二種做法是使用 context.Entry(department3).State = Microsoft.EntityFrameworkCore.EntityState.Modified; 這樣的敘述,通知 Entity Framework Core 的變更追蹤系統,有一筆紀錄要更新到資料庫內。

不論是哪種做法,最後都要 呼叫 context.SaveChanges() 方法

上面的程式會再度查詢資料庫內所有科系的紀錄,並且顯示在螢幕上,底下是執行結果

科系名稱:使用狀態來修改的科系名稱




2020年10月20日 星期二

Entity Framework Core EF Core 的 紀錄新增

Entity Framework Core EF Core 的 紀錄新增

在上一篇 EF Core 討論文章 Entity Framework Core 一對多的資料讀取 ,說明了如何使用 EF Core 來取得導航屬性內的關聯紀錄做法。

在這篇文章中,來了解如何使用 EF Core 來進行記錄新增動作的作法,關於更多這方面的應用,可以參考 基本儲存 這份文件內容。

請按照底下的步驟來進行操作

建立練習專案

  • 打開 Visual Studio 2019

  • 點選 [建立新的專案] 按鈕

  • 在 [建立新專案] 對話窗內,選擇 [Blazor 應用程式] 專案樣板

  • 在 [設定新的專案] 對話窗內,於 [專案名稱] 欄位內輸入 efAddRecord

  • 在 [建立新的 Blazor 應用程式] 對話窗內,選擇 [Blazor 伺服器應用程式] 這個選項

    在該對話窗右半部的其他選項,可以不用變更

  • 點選 [建立] 按鈕,以便開始建立這個專案

加入 Entity Framework Core 要使用到的 NuGet 套件

  • 滑鼠右擊專案內的 [相依性] 節點
  • 選擇 [管理 NuGet 套件]
  • 點選 [瀏覽] 標籤分頁頁次
  • 在 [搜尋] 文字輸入盒內,輸入 [Microsoft.EntityFrameworkCore.SqlServer]
  • 點選 [安裝] 按鈕以便安裝這個套件
  • 在 [搜尋] 文字輸入盒內,輸入 [Microsoft.EntityFrameworkCore.Tools]
  • 點選 [安裝] 按鈕以便安裝這個套件

使用反向工程來產生 Entity Framework 要用到的 Entity 模型相關類別

  • 切換到 [套件管理器主控台] 視窗

    若沒有看到 [套件管理器主控台] 視窗,點選功能表 [工具] > [NuGet 套件管理員] > [套件管理器主控台]

  • 在 [套件管理器主控台] 輸入底下內容

    因為都在同一個專案內,所以,這裡可以省略 StartupProject & Project 這兩個參數,因此,底下的指令會更為精簡

Scaffold-DbContext "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=School" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -f

請打開這個 [Program.cs] 檔案,完成底下的程式碼

var context = new DataContext();
Department department1 = new Department()
{
    Name = "新增的科系1",
};
context.Department.Add(department1);
context.SaveChanges();
Department department2 = new Department()
{
    Name = "新增的科系2",
};
context.Entry(department2).State = Microsoft.EntityFrameworkCore.EntityState.Added;
context.SaveChanges();
foreach (var item in context.Department.ToList())
{
    Console.WriteLine($"科系名稱:{item.Name}");
}

上面的程式碼說明了兩種新增記錄到後端資料庫內的作法,其實這兩種作法都是相同的,不論是哪一種做法,首先需要建立一個 Entity 類別的執行個體,這裡是要新增兩筆科系的紀錄,因此,需要使用 new 運算子來建立 Department 類別的物件。

一旦 Entity 的物件產生完成之後,便可以使用這樣的作法 context.Department.Add(department1) 將剛剛建立的物件,通知 EF Core 要準備把這個物件新增到資料庫內,最後,呼叫 context.SaveChanges(); 便會把 Entity Framework Core 內的變更追蹤的紀錄比對一次,便會發現到有要新增一筆紀錄的請求,接著便會產生 Insert SQL 敘述,把這個物件新增到資料庫內,成為一筆新的紀錄。

第二種作法那就是使用 context.Entry(department2).State = Microsoft.EntityFrameworkCore.EntityState.Added; 這樣的作法,宣告這個物件需要在下次呼叫 SaveChanges 的時候,將這個物件新增到資料庫內。

上面的程式會再度查詢資料庫內所有科系的紀錄,並且顯示在螢幕上,底下是執行結果

科系名稱:新增的科系1 

科系名稱:新增的科系2 




2020年10月19日 星期一

Entity Framework Core 一對多的資料讀取

 

Entity Framework Core 一對多的資料讀取

在上一篇 EF Core 討論文章 在 ASP.NET Core 專案內,建立其他日誌輸出設備 ,說明了如何透過 ILogger 來觀察 EF Core 產出了哪些 SQL 命到到 SQL Server 內。

在這篇文章中,來了解如何使用 EF Core 來讀取不同資料表內的關聯紀錄。

關於更多這方面的應用,可以參考 載入相關資料 這份文件內容。

請按照底下的步驟來進行操作

建立練習專案

  • 打開 Visual Studio 2019

  • 點選 [建立新的專案] 按鈕

  • 在 [建立新專案] 對話窗內,選擇 [Blazor 應用程式] 專案樣板

  • 在 [設定新的專案] 對話窗內,於 [專案名稱] 欄位內輸入 EFRelation

  • 在 [建立新的 Blazor 應用程式] 對話窗內,選擇 [Blazor 伺服器應用程式] 這個選項

    在該對話窗右半部的其他選項,可以不用變更

  • 點選 [建立] 按鈕,以便開始建立這個專案

加入 Entity Framework Core 要使用到的 NuGet 套件

  • 滑鼠右擊專案內的 [相依性] 節點
  • 選擇 [管理 NuGet 套件]
  • 點選 [瀏覽] 標籤分頁頁次
  • 在 [搜尋] 文字輸入盒內,輸入 [Microsoft.EntityFrameworkCore.SqlServer]
  • 點選 [安裝] 按鈕以便安裝這個套件
  • 在 [搜尋] 文字輸入盒內,輸入 [Microsoft.EntityFrameworkCore.Tools]
  • 點選 [安裝] 按鈕以便安裝這個套件

使用反向工程來產生 Entity Framework 要用到的 Entity 模型相關類別

  • 切換到 [套件管理器主控台] 視窗

    若沒有看到 [套件管理器主控台] 視窗,點選功能表 [工具] > [NuGet 套件管理員] > [套件管理器主控台]

  • 在 [套件管理器主控台] 輸入底下內容

    因為都在同一個專案內,所以,這裡可以省略 StartupProject & Project 這兩個參數,因此,底下的指令會更為精簡

Scaffold-DbContext "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=School" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -f

請打開這個 [Program.cs] 檔案,完成底下的程式碼

SchoolContext SchoolContext = new SchoolContext();
var allCourse = await SchoolContext.Course
    .AsNoTracking()
    .ToListAsync();
foreach (var itemCourse in allCourse)
{
    Console.WriteLine($"Course : {itemCourse.Title}");
    if(itemCourse.Department!= null)
    {
        Console.WriteLine($"Department : {itemCourse.Department.Name}");
    }
}

沒有指定使用何種方式載入關聯資料

從上面的程式碼將會看到,這裡會將所有的 課程 紀錄都讀取到 allCourse 這個集合物件內,並且使用 foreach 逐一將該課程紀錄與每個課程所指派的科系名稱顯示在螢幕上,不過,若該課程沒有指派任何科系紀錄,將不會看到這些科系名稱紀錄(在資料庫內因為有設定限制約束條件,因此,不會有這樣的課程與科系關聯存在)。在這裡的程式碼也會檢查,若科系物件不存在,則不會列印出科系名稱的資料。

實際執行這樣的程式碼,會發現到如下執行結果

Course : Calculus
Course : Chemistry
Course : Physics
Course : Composition
Course : Poetry
Course : Literature
Course : Trigonometry
Course : Microeconomics
Course : Macroeconomics
Course : Quantitative

這樣的執行結果與實際在資料庫到的紀錄有所不同,因為,在資料庫內,每個課程都會對應到一個科系。

使用明確式載入 Explicit Loading

首先,來使用 明確式載入 來解決此一問題。

請將程式碼修改成為如下

SchoolContext SchoolContext = new SchoolContext();
var allCourse = await SchoolContext.Course
    .ToListAsync();
foreach (var itemCourse in allCourse)
{
    Console.WriteLine($"Course : {itemCourse.Title}");
    SchoolContext.Entry(itemCourse)
        .Reference(b => b.Department)
        .Load();
 
    if(itemCourse.Department!= null)
    {
        Console.WriteLine($"Department : {itemCourse.Department.Name}");
    }
}

實際執行這樣的程式碼,會發現到如下執行結果

Course : Calculus
Department : Mathematics
Course : Chemistry
Department : Engineering
Course : Physics
Department : Engineering
Course : Composition
Department : English
Course : Poetry
Department : English
Course : Literature
Department : English
Course : Trigonometry
Department : Mathematics
Course : Microeconomics
Department : Economics
Course : Macroeconomics
Department : Economics
Course : Quantitative
Department : Economics

現在終於可以看到科系資料了,這裡對於程式碼做了兩個修正,首先原先程式碼在讀取課程資料的時候,有使用了 .AsNoTracking() 這個呼叫方法 ,這裡宣告了不要使用 EF Core 的追蹤功能,也就是 追蹤與 No-Tracking 的查詢 所說明的內容。可是,若加入了這個方法呼叫,將會造成底下的例外異常。

會有這樣的情況發生,這是因為有使用了 .Load() 方法,告知要使用明確式載入關聯紀錄,不過,若要使用這樣的功能,所查詢出來的紀錄,必須要納入 EF Core 變更追蹤內,否則,就會拋出這樣的例外異常。因此,這裡就會將 .AsNoTracking() 方法呼叫移除了。

System.InvalidOperationException
  HResult=0x80131509
  Message=Navigation property 'Department' on entity of type 'Course' cannot be loaded because the entity is not being tracked. Navigation properties can only be loaded for tracked entities.
  Source=Microsoft.EntityFrameworkCore
  StackTrace: 
   at Microsoft.EntityFrameworkCore.Internal.EntityFinder`1.Load(INavigation navigation, InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.NavigationEntry.Load()
   at EFRelation.Program.<Main>d__0.MoveNext() in D:\Vulcan\GitHub\Blazor-HOL\Labs\EFRelation\EFRelation\Program.cs:line 20

另外,當每一筆課程紀錄讀取出來之後,使用 Collection 或者 Reference 這兩個方法,說明要明確地載入集合或這單一導覽屬性,最後,呼叫 Load 方法,就會送出 SQL 敘述到資料庫內,讀取相關科系紀錄出來。

使用積極式載入 Eager Loading

對於 積極式載入 這樣的做法則是另外一種不錯的選擇,可以在讀取全部課程紀錄的時候,一併讀取出相關的科系記錄出來。

請將程式碼修改成為如下

SchoolContext SchoolContext = new SchoolContext();
var allCourse = await SchoolContext.Course
    .AsNoTracking()
    .Include(x=>x.Department)
    .ToListAsync();
foreach (var itemCourse in allCourse)
{
    Console.WriteLine($"Course : {itemCourse.Title}");
    if(itemCourse.Department!= null)
    {
        Console.WriteLine($"Department : {itemCourse.Department.Name}");
    }
}

實際執行這樣的程式碼,會發現到如下執行結果

Course : Calculus
Department : Mathematics
Course : Chemistry
Department : Engineering
Course : Physics
Department : Engineering
Course : Composition
Department : English
Course : Poetry
Department : English
Course : Literature
Department : English
Course : Trigonometry
Department : Mathematics
Course : Microeconomics
Department : Economics
Course : Macroeconomics
Department : Economics
Course : Quantitative
Department : Economics

在使用 積極式載入 做法中,將會使用 Include 方法指定要同時載入那些導航屬性的紀錄。










2020年10月14日 星期三

在 ASP.NET Core 專案內,建立其他日誌輸出設備

在 ASP.NET Core 專案內,建立其他日誌輸出設備

根據 上一篇 EF Core 討論文章 在 ASP.NET Core Blazor 專案內,觀察送出的 SQL 敘述 ,了解到如何透過 [appsettings.Development.json] 來指定與過濾那些等級的日誌要記錄下來。。

在這篇文章中,來了解如何在 ASP.NET Core 的專案內,可以指定多個日誌 Log 輸出對象的作法。

關於更多這方面的應用,可以參考 .NET Core 與 ASP.NET Core 中的記錄 這份文件內容。

這裡的練習專案原始碼,將會延續 在 ASP.NET Core Blazor 專案內,觀察送出的 SQL 敘述 文件中使用的專案原始碼。

請打開這個 efBlazorLogging 專案

在專案根目錄下找到並打開 [Program.cs] 這個檔案

將這個檔案的內容,修改成為如下的程式碼

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace efBlazorLogging
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .ConfigureLogging((context, logging) =>
            {
                // Console
                logging.AddConsole();
                // Debug
                logging.AddDebug();
                // Event Source
                logging.AddEventSourceLogger();
                // Event Log
                logging.AddEventLog();
            })
            .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}

在 [CreateHostBuilder] 方法內,呼叫了 [ConfigureLogging] 方法,在這裏面指定了 Console, Debug, Event Source, Event Log 這四個對象做為要輸出日誌的目的。

另外,請打開 [appsettings.Development.json] 檔案

  • 在這個檔案內,加入一個屬性 : EventLog 節點,如底下清單所示
{
  "DetailedErrors": true,
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      //"Microsoft.EntityFrameworkCore": "Trace",
      "Microsoft.EntityFrameworkCore": "Information",
      "Microsoft.Hosting.Lifetime": "Information"
    },
    "EventLog": {
      "LogLevel": {
        "Default": "Information",
        "Microsoft.Hosting.Lifetime": "Information",
        "Microsoft.EntityFrameworkCore": "Information"
      }
    }
  }
}
  • 執行一次這個專案,並且點選讀取資料庫的按鈕
  • 此時,從 Console 視窗內將會看到底下內容
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: D:\Vulcan\GitHub\CSharp2020\efBlazorLogging\efBlazorLogging
info: efBlazorLogging.Pages.Index[0]
      開始讀取資料庫
info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
      Entity Framework Core 3.1.8 initialized 'SchoolContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer' with options: None
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (56ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT [p].[PersonID], [p].[EnrollmentDate], [p].[FirstName], [p].[HireDate], [p].[LastName]
      FROM [Person] AS [p]

另外,在 Visual Studio 的輸出視窗內,將會看到底下的內容

Visual Studio 輸出視窗

...
Microsoft.EntityFrameworkCore.Database.Command: Information: Executed DbCommand (40ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT [p].[PersonID], [p].[EnrollmentDate], [p].[FirstName], [p].[HireDate], [p].[LastName]
FROM [Person] AS [p]
'[21996] efBlazorLogging.exe: 程式追蹤' 程式以返回碼 0 (0x0) 結束。
'[21996] efBlazorLogging.exe' 程式以返回碼 -1 (0xffffffff) 結束。

打開電腦中的事件檢視器軟體,點選 [Windows紀錄] > [應用程式] 節點,將會看到許多 .NET Runtime 的事件,如下圖所示

事件檢視器 Event Log

請找到有 Category: Microsoft.EntityFrameworkCore.Database.Command 內容的事件項目,點兩下打開這個節點,將會看到如下內容

事件檢視器 Event Log

記錄檔名稱:         Application
來源:            .NET Runtime
日期:            2020/10/10 下午 06:32:37
事件識別碼:         1000
工作類別:          無
層級:            資訊
關鍵字:           傳統
使用者:           不適用
電腦:            DESKTOP-CVIR8LH
描述:
Category: Microsoft.EntityFrameworkCore.Database.Command
EventId: 20101
ConnectionId: 0HM3D0V5TMI98
RequestId: 0HM3D0V5TMI98:00000001
RequestPath: /_blazor
SpanId: |bef0ec8d-46959f4e11a6541a.
TraceId: bef0ec8d-46959f4e11a6541a
ParentId: 
TransportConnectionId: bW06WGREXKM8jJKZJkSU7w

Executed DbCommand (40ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT [p].[PersonID], [p].[EnrollmentDate], [p].[FirstName], [p].[HireDate], [p].[LastName]
FROM [Person] AS [p]

事件 Xml:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
  <System>
    <Provider Name=".NET Runtime" />
    <EventID Qualifiers="0">1000</EventID>
    <Version>0</Version>
    <Level>4</Level>
    <Task>0</Task>
    <Opcode>0</Opcode>
    <Keywords>0x80000000000000</Keywords>
    <TimeCreated SystemTime="2020-10-10T10:32:37.5318663Z" />
    <EventRecordID>21976</EventRecordID>
    <Correlation />
    <Execution ProcessID="0" ThreadID="0" />
    <Channel>Application</Channel>
    <Computer>DESKTOP-CVIR8LH</Computer>
    <Security />
  </System>
  <EventData>
    <Data>Category: Microsoft.EntityFrameworkCore.Database.Command
EventId: 20101
ConnectionId: 0HM3D0V5TMI98
RequestId: 0HM3D0V5TMI98:00000001
RequestPath: /_blazor
SpanId: |bef0ec8d-46959f4e11a6541a.
TraceId: bef0ec8d-46959f4e11a6541a
ParentId: 
TransportConnectionId: bW06WGREXKM8jJKZJkSU7w

Executed DbCommand (40ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT [p].[PersonID], [p].[EnrollmentDate], [p].[FirstName], [p].[HireDate], [p].[LastName]
FROM [Person] AS [p]
</Data>
  </EventData> 

</Event>