You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Entity Framework Core:C#生成Guid时如何实现Upsert操作?

Solutions for Client-Generated Guid Upsert in EF Core

Absolutely, you can implement Upsert operations when using client-generated Guid keys in EF Core—Attach and Update fall short here because they assume the entity's existence state is known, but we can work around this with a few reliable approaches:

Option 1: Query-First Check (Simple & Intuitive)

This is the most straightforward approach: first check if the Guid exists in the database, then either update the existing record or insert a new one.

using (var context = new YourDbContext())
{
    // Your entity with client-generated Guid
    var targetEntity = new Product 
    { 
        Id = Guid.Parse("your-client-generated-guid"), 
        Name = "Updated Product Name",
        Price = 29.99m
    };

    var existingEntity = context.Products.Find(targetEntity.Id);
    if (existingEntity != null)
    {
        // Update all scalar properties from the target entity
        context.Entry(existingEntity).CurrentValues.SetValues(targetEntity);
    }
    else
    {
        // No matching record found—insert new
        context.Products.Add(targetEntity);
    }

    await context.SaveChangesAsync();
}

Pros: Easy to read, maintains EF Core's ORM benefits, works with all EF Core versions.
Cons: Adds an extra database round-trip for the existence check (negligible for most small-to-medium workloads).

Option 2: Native SQL MERGE (Performance-Focused)

For scenarios where you need minimal database trips (e.g., bulk operations), use SQL's MERGE statement directly. This handles the upsert in a single database call.

using (var context = new YourDbContext())
{
    var targetEntity = new Product 
    { 
        Id = Guid.Parse("your-client-generated-guid"), 
        Name = "Updated Product Name",
        Price = 29.99m
    };

    var mergeSql = @"
        MERGE INTO Products AS Target
        USING (VALUES (@Id, @Name, @Price)) AS Source (Id, Name, Price)
        ON Target.Id = Source.Id
        WHEN MATCHED THEN
            UPDATE SET Name = Source.Name, Price = Source.Price
        WHEN NOT MATCHED THEN
            INSERT (Id, Name, Price) VALUES (Source.Id, Source.Name, Source.Price);";

    await context.Database.ExecuteSqlRawAsync(mergeSql,
        new SqlParameter("@Id", targetEntity.Id),
        new SqlParameter("@Name", targetEntity.Name),
        new SqlParameter("@Price", targetEntity.Price));
}

Pros: Single database operation, ideal for bulk upserts or high-throughput scenarios.
Cons: Requires writing raw SQL (loses some ORM portability across database providers).

Why Attach and Update Don’t Work for This

  • Attach marks the entity as Unchanged—EF Core won’t generate any SQL for it during SaveChanges because it assumes the entity matches the database state.
  • Update marks the entity as Modified, but if the Guid doesn’t exist in the database, EF Core will throw a DbUpdateConcurrencyException (or similar) since it expects the record to be present.

Both methods lack the built-in logic to check for existence and switch between insert/update, which is exactly what Upsert requires.


内容的提问来源于stack exchange,提问作者William Jockusch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:59:26