「Entity Framework Core」(別名EF7)で「ソフト削除」を実装するにはどうすればよいですか?

c# entity-framework-core

質問

私はEF7を使用して "ソフト削除"を実装しようとしています。 My Itemテーブルには、 bitタイプのIsDeletedという名前のフィールドがあります。私がSOや他の場所で見ている例はすべて、次のようなものを使用しています。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Item>().Map(m => m.Requires("IsDeleted").HasValue(false));
}

Map()はもはやModelBuilderメソッドではありModelBuilder

編集:私を明確にさせてください。私はほとんどのデータを今読んで興味を持っています。私はEFが自動的にIsDeleted == 1 (またはtrue)のItemテーブル内のすべてのレコードをフィルタリングしてほしいと思います。私はすべてのクエリの最後に&& x.IsDeleted == falseを必要としたくありません。

エキスパート回答

免責事項 :私はEntity Framework Plusプロジェクトのオーナーです

@Ademリンクのように、私たちのライブラリはクエリフィルタリングをサポートしています。

グローバル/インスタンスフィルタを簡単に有効/無効にすることができます

QueryFilterManager.Filter<Item>(q => q.Where(x => !x.IsDeleted));

Wiki: EFクエリフィルタ

編集 :回答のサブ質問

このことがシーンの背後でどのように機能するかを説明するためのケア?

まず、フィルタをグローバルに初期化するか、インスタンスごとに初期化するか

// Filter by global configuration
QueryFilterManager.Filter<Customer>(q => q.Where(x => x.IsActive));
var ctx = new EntitiesContext();
// TIP: You can also add this line in EntitiesContext constructor instead
QueryFilterManager.InitilizeGlobalFilter(ctx);

// Filter by instance configuration
var ctx = new EntitiesContext();
ctx.Filter<Post>(MyEnum.EnumValue, q => q.Where(x => !x.IsSoftDeleted)).Disable();

このライブラリでは、ライブラリはコンテキストのすべてのDbSetをループし、フィルタをジェネリック型に適用できるかどうかをチェックします。

この場合、ライブラリは、フィルタを使用してDbSetから元の/フィルタを適用したクエリをフィルタ処理し、新しいフィルタされたクエリの現在の内部クエリを変更します。

要約すると、フィルタ処理されたクエリを使用するために、一部のDbSet内部値を変更しました。

どのように動作するかを知りたい場合は、コードはフリーオープンソースです。

編集 :回答のサブ質問

@jonathanはこのフィルタにナビゲーションコレクションも含めますか?

EF Coreの場合、Interceptorはまだ使用できないため、まだサポートされていません。しかし、EF Core 2.xから始めて、EFチームはこれを可能にするグローバルクエリフィルタを実装しました。


人気のある回答

EF Core 2.0に移行できる場合は、モデルレベルのクエリフィルタを使用できます。https://docs.microsoft.com/en-us/ef/core/what-is-new/index

EF Core 1.0を使用している場合使用可能なEF Core機能でいくつかのトリックを行うことができます:

継承https://docs.microsoft.com/en-us/aspnet/core/data/ef-mvc/inheritance

シャドウプロパティhttps://docs.microsoft.com/en-us/ef/core/modeling/shadow-properties

public class Attachment : AttachmentBase
{}

public abstract class AttachmentBase
{
    public const string StatePropertyName = "state";

    public Guid Id { get; set; }
}

public enum AttachmentState
{
    Available,
    Deleted
}

public class AttachmentsDbContext : DbContext
{
    public AttachmentsDbContext(DbContextOptions options)
        : base(options)
    {
    }

    public DbSet<Attachment> Attachments { get; set; }

    public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
    {
        IEnumerable<EntityEntry<Attachment>> softDeletedAttachments = ChangeTracker.Entries<Attachment>().Where(entry => entry.State == EntityState.Deleted);

        foreach (EntityEntry<Attachment> softDeletedAttachment in softDeletedAttachments)
        {
            softDeletedAttachment.State = EntityState.Modified;
            softDeletedAttachment.Property<int>(AttachmentBase.StatePropertyName).CurrentValue = (int)AttachmentState.Deleted;
        }
        return base.SaveChangesAsync(cancellationToken);
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<AttachmentBase>()
            .HasDiscriminator<int>(AttachmentBase.StatePropertyName)
            .HasValue<Attachment>((int)AttachmentState.Available);

        modelBuilder.Entity<AttachmentBase>().Property<int>(AttachmentBase.StatePropertyName).Metadata.IsReadOnlyAfterSave = false;

        modelBuilder.Entity<Attachment>()
            .ToTable("available_attachment");

        modelBuilder.Entity<AttachmentBase>()
            .ToTable("attachment");

        base.OnModelCreating(modelBuilder);
    }
}


Related

ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ