星期三, 3月 19, 2025

[EFCore] 陰影屬性

通常 EF Entity Property 會對應 Table Column,但透過陰影屬性 (Shadow Property) 可以讓該 EF Entity 沒有該 Property,但卻還是可以對應 Table Column。 適用場景在於 Table 常設的 CreateTime、ModifiedDate 欄位或是資料軟刪除欄位

Shadow Property 設定

在 DbContext 內的 OnModelCreating 中透過 Fluent API 來進行設定
public partial class AdventureWorks2022DbContext : DbContext
{
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Person>()
            .Property<DateTime>("ModifiedDate");
    }
}

C# Code

namespace EFCoreShadowProperty
{
    internal class Program
    {
        static void Main(string[] args)
        {
            string shadowPropertyName = "ModifiedDate";

            var dbContext = new AdventureWorks2022DbContext();

            Console.WriteLine("---------- 在 OrderBy 中使用 EF.Property 來抓取 Shadow Property");
            var person = dbContext
                .Person
                .OrderBy(p => EF.Property<DateTime>(p, shadowPropertyName))
                .FirstOrDefault();

            // 取值並顯示
            var modifyDate = dbContext.Entry(person).Property(shadowPropertyName).CurrentValue;
            Console.WriteLine($"---------- 修改時間最早的資料:{person.LastName}-{person.FirstName}-{modifyDate}");

            Console.WriteLine($"---------- 設定 Shadow Property 值並儲存");
            // 設定值並儲存
            DateTime now = DateTime.Now;
            dbContext.Entry(person).Property(shadowPropertyName).CurrentValue = now;
            dbContext.SaveChanges();

            Console.WriteLine($"---------- 在 Where 中使用 EF.Property 來抓取 Shadow Property");
            var updatePerson = dbContext
                .Person
                .Where(p => EF.Property<DateTime>(p, shadowPropertyName) == now)
                .ToList();
        }
    }
}

輸出結果觀察


設定 [EFCore] LogTo 來觀察 Shadow Property 所產生的 TSQL,以下有把輸出資訊簡化,方便閱讀
---------- 在 OrderBy 中使用 EF.Property 來抓取 Shadow Property

SELECT TOP(1) 欄位名稱
FROM [Person].[Person] AS [p]
ORDER BY [p].[ModifiedDate]

---------- 修改時間最早的資料:Tamburello-Roberto-2007/11/4 上午 12:00:00

---------- 設定 Shadow Property 值並儲存

SET IMPLICIT_TRANSACTIONS OFF;
SET NOCOUNT ON;
UPDATE [Person].[Person] SET [ModifiedDate] = @p0
WHERE [BusinessEntityID] = @p1;
SELECT @@ROWCOUNT;

---------- 在 Where 中使用 EF.Property 來抓取 Shadow Property

SELECT 欄位名稱
FROM [Person].[Person] AS [p]
WHERE [p].[ModifiedDate] = @__now_0

星期六, 3月 15, 2025

[Azure] Notifications - Pull Request

在 Azure DevOps 上設定 PR 通知,當 PR 建立時可以發信通知該 Project 相關成員

Project Setting => Notifications => New subscription

Code (Git) => A pull request is created or updated

subscription 相關設定,分別為
  • Description:修改為方便辨識名稱
  • Deliver to:選擇 Member of Project Team,預設是根據 Role
  • Filter:A specific team project:選擇特定專案
Filter criteria 為發信條件,紀錄兩種觸發方式
  • Event Type = Pull request created
  • Status changes to Completed
兩者差異在於發出訊息內容,Pull request created 內會包含 Reviewer、檔案變更、Commits 資訊,Status changes to Completed 只有 Reviewer

下圖為官方文章 - Create an email subscription 發信條件

星期五, 3月 14, 2025

[Azure] Contact email

 Azure DevOps 上登錄信箱即為聯絡信箱,但可以在 User Setting => Profile => Contact email 內去進行修改

星期四, 3月 13, 2025

[Outlook] 轉寄

在 Outlook 內設定,要把收到信件轉寄到指定信箱去

設定 => 郵件 => 轉寄 => 啟用轉寄並輸入信箱,這樣寄到 Outlook 信箱的信件就會轉寄到指定信箱,另外也可以透過設定規則,符合規則才進行轉寄

星期二, 3月 11, 2025

[EFCore] LogTo

根據官方文章 Simple Logging 內容,要在 Console 上顯示 Linq to Entity 產生的 TSQL 語法。

只要在 DbContext.OnConfiguring() 內進行 LogTo 設定,語法如下
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder.UseSqlServer(連線字串)
        .LogTo(Console.WriteLine , LogLevel.Information);
        // 或
        .LogTo(message => Console.WriteLine(message) , LogLevel.Information);
萬一沒有指定 LogLevel.Infomation 會輸出過多訊息,變得不容易找到 TSQL 語法
info: 2025/3/11 08:41:31.472 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command) Executed DbCommand (12ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] SELECT [p].[BusinessEntityID], [p].[AdditionalContactInfo], [p].[Demographics], [p].[EmailPromotion], [p].[FirstName], [p].[LastName], [p].[MiddleName], [p].[ModifiedDate], [p].[NameStyle], [p].[PersonType], [p].[Suffix], [p].[Title], [p].[rowguid] FROM [Person].[Person] AS [p]
文章內還其他輸出模式、顯示機密資料和篩選資訊相關可以參考。