EF CORE 7の新機能-ExecuteDeleteとExecuteUpdateを使用した一括操作

EF CORE 7の新機能-ExecuteDeleteとExecuteUpdateを使用した一括操作

Entity Framework 7には、すでに要求されている一般的な機能がいくつかあります。

最后更新 2022/09/10 22:55
tim_deschryver
预计阅读 5 分钟
分类
EF Core
标签
.NET C# EF Core ORM

原文链接:https://timdeschryver.dev/blog/new-in-entity-framework-7-bulk-operations-with-executedelete-and-executeupdate

アーティスト:Tim_Deschryver

砂漠の果ての狼

Entity Framework 7 包括一些已被要求的流行功能,其中之一是批量操作。Julie Lerman 的一条推文引起了我的注意,我不得不亲自尝试一下。

推文地址:https://twitter.com/julielerman/status/1557743067691569156

https://twitter.com/julielerman/status/1557743067691569156

CLARiXの理由

では、すでにエンティティを更新および削除できるのに、なぜこの機能が必要なのでしょうか?ここでのキーワードは性能です。これはEFの新バージョンで常にトップに立っているテーマであり、今回も例外ではない。

追加された方法は、さまざまな方法でパフォーマンスを向上させます。最初にエンティティを取得してすべてのエンティティをメモリに格納するのではなく、操作を実行してSQLに送信します。今では、SQLコマンドを生成する1つの操作でこれを行うことができます。

コードでどうなるか見てみましょう。

シーンを設定する

例に入る前に、SQLデータベースを構成し、3つのテーブルを入力しましょう:

  • Personsの人
  • Addresses住所1人に1つの住所がある
  • Pets:ペット(一人でたくさんのペットを飼うことができる)
using Microsoft.EntityFrameworkCore;

using (var context = new NewInEFContext())
{
    SetupAndPopulate(context);
}

static void SetupAndPopulate(NewInEFContext context)
{
    context.Database.EnsureDeleted();
    context.Database.EnsureCreated();
    context.Persons.AddRange(Enumerable.Range(1, 1_000).Select(i =>
    {
        return new Person
        {
            FirstName = $"{nameof(Person.FirstName)}-{i}",
            LastName = $"{nameof(Person.LastName)}-{i}",
            Address = new Address
            {
                Street = $"{nameof(Address.Street)}-{i}",
            },
            Pets = Enumerable.Range(1, 3).Select(i2 =>
            {
                return new Pet
                {
                    Breed = $"{nameof(Pet.Breed)}-{i}-{i2}",
                    Name = $"{nameof(Pet.Name)}-{i}-{i2}",
                };
            }).ToList()
        };
    }));

    context.SaveChanges();
}

public class NewInEFContext : DbContext
{
    public DbSet<Person> Persons { get; set; }
    public DbSet<Pet> Pets { get; set; }
    public DbSet<Address> Addresses { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options
            .UseSqlServer("Connectionstring");

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Address>()
           .Property<long>("PersonId");

        modelBuilder.Entity<Pet>()
            .Property<long>("PersonId");
    }
}

public class Person
{
    public long PersonId { get; set; }
    public string FirstName { get; set; } = "";
    public string LastName { get; set; } = "";
    public Address? Address { get; set; }
    public List<Pet> Pets { get; set; } = new List<Pet>();
}

public class Address
{
    public long AddressId { get; set; }
    public string Street { get; set; } = "";
}

public class Pet
{
    public long PetId { get; set; }
    public string Breed { get; set; } = "";
    public string Name { get; set; } = "";
}

ExecuteDeleteとExecuteDeleteAsync

既然我们已经解决了这个问题,让我们深入研究ExecuteDeleteExecuteDeleteAsync

要批量删除一组实体,请使用Where方法过滤掉要删除的实体(与之前类似)。然后,调用ExecuteDelete方法删除实体集合。

using (var context = new NewInEFContext())
{
    SetupAndPopulate(context);

    context.Pets
           .Where(p => p.Name.Contains("1"))
           .ExecuteDelete();
}

生成されるSQLステートメントも見てみましょう:

DELETE FROM [p]
FROM [Pets] AS [p]
WHERE [p].[Name] LIKE N'%1%'

ご覧の通り、適格なエンティティを削除するSQLステートメントを生成するだけです。これらのエンティティもメモリに保存されなくなります。シンプルで効率的です!

カスケード削除#カスケードサクセイ#

別の例を見てみましょう。住所とペットの参照を持っている人を削除しましょう。削除文が外部テーブルにカスケードされるため、人を削除することで、アドレスとペットも削除されます。

using (var context = new NewInEFContext())
{
    SetupAndPopulate(context);

    context.Persons
           .Where(p => p.PersonId <= 500)
           .ExecuteDelete();
}

以前と同様に、次のSQL文が生成されます。

DELETE FROM [p]
FROM [Persons] AS [p]
WHERE [p].[PersonId] <= CAST(500 AS bigint)

影響を受けた行数

还可以查看删除操作影响了多少行,ExecuteDelete返回受影响的行数。

using (var context = new NewInEFContext())
{
    SetupAndPopulate(context);

    var personsDeleted =
        context.Persons
           .Where(p => p.PersonId <= 100)
           .ExecuteDelete();
}

在上面的表达式中,personsDeleted变量等于 100。

ExecuteUpdateとExecuteUpdateAsync

现在我们已经了解了如何删除实体,让我们探索如何更新它们。就像ExecuteDelete,我们首先必须过滤我们想要更新的实体,然后调用ExecuteUpdate.

要更新实体,我们需要使用新SetProperty方法。SetProperty的第一个参数是通过 lambda 选择需要更新的属性,第二个参数也使用 lambda 选择该属性的新值,。

たとえば、ユーザの姓を“Updated”に設定します。

using (var context = new NewInEFContext())
{
    SetupAndPopulate(context);

    context.Persons
           .Where(p => p.PersonId <= 1_000)
           .ExecuteUpdate(p => p.SetProperty(x => x.LastName, x => "Updated"));
}

これにより、適切なSQL文が生成されます。

UPDATE [p]
    SET [p].[LastName] = N'Updated'
FROM [Persons] AS [p]
WHERE [p].[PersonId] <= CAST(1000 AS bigint)

エンティティの値にアクセスして、新しい値を作成するために使用することもできます。

using (var context = new NewInEFContext())
{
    SetupAndPopulate(context);

    context.Persons
           .Where(p => p.PersonId <= 1_000)
           .ExecuteUpdate(p => p.SetProperty(x => x.LastName, x => "Updated" + x.LastName));
}

次のSQL文を生成します。

UPDATE [p]
    SET [p].[LastName] = N'Updated' + [p].[LastName]
FROM [Persons] AS [p]
WHERE [p].[PersonId] <= CAST(1000 AS bigint)

複数の値を一度に更新

我们甚至可以通过多次调用SetProperty来一次更新多个属性。

using (var context = new NewInEFContext())
{
    SetupAndPopulate(context);

    context.Persons
           .Where(p => p.PersonId <= 1_000)
           .ExecuteUpdate(p =>
                p.SetProperty(x => x.LastName, x => "Updated" + x.LastName)
                 .SetProperty(x => x.FirstName, x => "Updated" + x.FirstName));
}

再び、対応するSQLステートメント:

UPDATE [p]
    SET [p].[FirstName] = N'Updated' + [p].[FirstName],
    [p].[LastName] = N'Updated' + [p].[LastName]
FROM [Persons] AS [p]
WHERE [p].[PersonId] <= CAST(1000 AS bigint)

影響を受けた行数

就像ExecuteDelete,ExecuteUpdate也返回受影响的行数。

using (var context = new NewInEFContext())
{
    SetupAndPopulate(context);

    var personsUpdated =
        context.Persons
           .Where(p => p.PersonId <= 1_000)
           .ExecuteUpdate(p => p.SetProperty(x => x.LastName, x => "Updated"));
}

ネストされたエンティティの更新はサポートされていないことに注意してください。

Entity Framework 7のその他のアップデート

有关新功能的完整列表,请参阅EF 7 计划

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 2022/06/02

EF Core 6の新機能概要(4)

この記事では、SQLite、インメモリプロバイダ、およびEF. Functions.Containsメソッドに対するEF Coreの改善点について説明します。

继续阅读
同分类 / 同标签 2022/06/02

EF Core 6の新機能概要(2)

前回の記事に続き、この記事では、バリューコンバータ、足場、Db Contextの改善など、EF Core 6の10の新機能を紹介します。

继续阅读
同分类 / 同标签 2022/06/02

EF Core 6の新機能の概要(1)

この記事では、EF Core 6の10の新機能について説明します。新機能、時制テーブル、スパース列のサポート、その他の新機能です。

继续阅读