EF.Coreは、複数のテーブルにマップするために同じモデルを使用します

EntityFrameworkコアでは、我々は、マッピングモデル属性や流暢APIを構成するために使用することができます。ある日、私は新たな需要を満たし、毎日大量のデータを生成するシステムは、毎日のデータを格納するために新しいテーブルを作成します。例えば、データベースは次の通り:

すべてのテーブルが同じ構造を持っています。だから、どのように複数のモデルが何作成されないようにするためにマップを変更するには?

この記事では、私はこのような状況に対処するためのマッピングを変更する方法を紹介します。あなたはまた、より多くの使用を拡張するために、このメソッドを使用することができます。

.NETのコア3.1プロジェクトの作成

今、私たちは、.NETのコア3.1を使用することができ、それはあなたが簡単に.NET 5にアップグレードすることができ、将来的に、.NETのコアのLTS版です。

お使いのコンピュータに最新の.NETのコアSDKをインストールしていると仮定。ない場合は、https://dotnet.microsoft.com/downloadからダウンロードすることができます。その後、使用することができdotnet CLI、プロジェクトを作成します。この例では、私は、.NETのコア3.1を使用します。

さんと呼ばれるファイルを作成してみましょうDynamicModelDemo新しい.NET Core Consoleのプロジェクトを:

dotnet new console --name DynamicModelDemo

次に、以下のコマンドを使用して新しいソリューションを作成します。

dotnet new sln --name DynamicModelDemo

次は、ソリューションに作成したばかりのアイテムを追加するには、次のコマンドを使用します。

dotnet sln add "DynamicModelDemo/DynamicModelDemo.csproj"

そして、あなたは、Visual Studioでソリューションを開くことができます。

モデルを作成します。

モデルは非常に単純です。で指定されたプロジェクトの追加ConfigurableEntity.cs新しいファイルを:

using System;

namespaceDynamicModelDemo
{
    publicclassConfigurableEntity
    {
        publicint Id { get; set; }
        publicstring Title { get; set; }
        publicstring Content { get; set; }
        public DateTime CreateDateTime { get; set; }
    }
}

私たちは、使用するCreateDateTimeテーブルにマップされるべきモデルを決定するためにプロパティを。

EntityFrameworkコアを追加

プロジェクトディレクトリに移動し、次のコマンドを使用して、必要なEF.Coreパッケージを追加することは:

dotnet add package Microsoft.EntityFrameworkCore.SqlSever
dotnet add package Microsoft.EntityFrameworkCore.Design

あなたはEFツールをインストールしていない場合は、インストールするには、次のコマンドを実行します。

dotnet tool install --global dotnet-ef

これは、作成またはDOTNET EF移行ツールを使用してデータベースを更新するための移行のアプリケーションを可能にします。

DbContextを作成します

呼ばれるプロジェクトに追加するDynamicContext.cs新しいクラスファイル。次のように示されます:

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using System;

namespaceDynamicModelDemo
{
    publicclassDynamicContext : DbContext
    {
        public DbSet<ConfigurableEntity> Entities { get; set; }

        #region OnConfiguring
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
            => optionsBuilder
                .UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=DynamicContext;Trusted_Connection=True;");
        #endregion

        #region OnModelCreating
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<ConfigurableEntity>(b =>
            {
                b.HasKey(p => p.Id);
            });
        }
        #endregion
    }
}

現時点では、これが唯一のEF.Coreの基本的な構成です。これは、モデルが名前にマッピングされることを意味し、デフォルトのマッピングを使用してEntities、テーブルの。だから、私たちが望む場合は、そのに基づいてCreateDateTimeそれを行う方法を、別のテーブルのプロパティにマップのモデルを?

あなたは私たちが使用できることを知っている可能性がありToTable()、テーブルのメソッドの名前を変更するが、どのようにしてOnModelCreating、それに近づくすべてのモデルのテーブル名を変更しますか?ときEFモデルのみOnModelCreating一回。したがって、この方法でそれを達成することができません。

この場合、当社は必要とIModelCacheKeyFactoryEFは、その属性に応じて異なるモデルを作成できるように、我々はモデルのキャッシュ機構をカスタマイズすることができ、それを通してデフォルトのマッピングを変更します。

IModelCacheKeyFactory何ですか?

これは、Microsoftの公式ドキュメントの説明です:

EFは、使用  IModelCacheKeyFactory モデルのためのキャッシュキーを生成します。

デフォルトでは、EFは、コンテキストモデルの任意の所与のタイプに対して同じであると仮定されます。それは別のテーブルにマップされているとしてではなく、我々のプログラムのために、モデルが異なることになります。したがって、我々は、実装交換する必要があるIModelCacheKeyFactoryサービスを、実装が正しいテーブルにモデルをマッピングする複数のキャッシュキーになります。

この手順は、通常、データベースが拡張インターフェースおよび他を提供し、アプリケーション・コードは、一般的に使用されていないことに留意されたいです。しかし、我々のシナリオのために、これは実行可能なアプローチです。

実現IModelCacheKeyFactory

私たちは、必要なCreateDateTimeテーブルを区別します。ではDynamicContext、プロパティクラスを追加します:

public DateTime CreateDateTime { get; set; }

で指定されたプロジェクトの追加DynamicModelCacheKeyFactory.cs新しいクラスファイルを。コードは次の通り:

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;

namespaceDynamicModelDemo
{
    publicclassDynamicModelCacheKeyFactory : IModelCacheKeyFactory
    {
        public object Create(DbContext context)
            => context is DynamicContext dynamicContext
                ? (context.GetType(), dynamicContext.CreateDateTime)
                : (object)context.GetType();
    }
}

モデルのキャッシュキーを作成している間、この実装が考慮されるCreateDateTimeプロパティ。

アプリケーションIModelCacheKeyFactory

次に、我々は新しいコンテキストを登録することができますIModelCacheKeyFactory

#region OnConfiguring
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
            => optionsBuilder
                .UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=DynamicContext;Trusted_Connection=True;")
                .ReplaceService<IModelCacheKeyFactory, DynamicModelCacheKeyFactory>();
#endregion

私たちができるようにOnModelCreatingする方法の各マッピングテーブル名:

#region OnModelCreating
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
      modelBuilder.Entity<ConfigurableEntity>(b =>
            {
                b.ToTable(CreateDateTime.ToString("yyyyMMdd"));
                b.HasKey(p => p.Id);
            });
}
#endregion

CreateDateTimeDynamicContextプロパティ。

私たちは、作成することができDynamicContext、指定された時間CreateDateTime属性を:

var context = new DynamicContext { CreateDateTime = datetime };

場合datetime2020/03/27は、contextモデルが名前にマッピングされる20200327テーブルの。

データベースを作成します。

検証コードの前に、我々は、データベースを作成する必要があります。時間が経つにつれて、システムは複数のテーブルを生成しますので、しかし、EFの移行は、このような状況のための最善の解決策ではありません。私たちは、マッピングテーブルを確認するために、いくつかのサンプルを作成するためにそれを使用するだけ。確かに、このシステムは、他の動的に生成されたテーブルに毎日を持っている必要があります。

最初の移行を作成するには、次のコマンドを実行します。

dotnet ef migrations add InitialCreate

あなたは、表示されるMigrationsフォルダ内の2つのファイルを生成します。開いxxx_InitialCreate.csたファイルを、次のコードでメソッドをアップ更新します。

protected override void Up(MigrationBuilder migrationBuilder)
{
      for (int i = 0; i < 30; i++)
      {
           var index = i;
           migrationBuilder.CreateTable(
               name: DateTime.Now.AddDays(-index).ToString("yyyyMMdd"),
               columns: table => new
               {
                    Id = table.Column<int>(nullable: false)
                            .Annotation("SqlServer:Identity", "1, 1"),
                    Title = table.Column<string>(nullable: true),
                    Content = table.Column<string>(nullable: true),
                    CreateDateTime = table.Column<DateTime>(nullable: false)
               },
               constraints: table =>
               {
                    table.PrimaryKey($"PK_{DateTime.Now.AddDays(-index):yyyyMMdd}", x => x.Id);
               });
        }
    }

変更は、データベースがテストのために十分なテーブルを持つことができるようにすることです。ことに注意してください私たちは、本番環境では、このアプローチを使用しないでください

次に、我々は作成し、データベースを更新するには、このコマンドを使用することができます。

dotnet ef database update

あなたはそれがデータベース内のテーブルの最後の30日間を生成していることがわかります。

マッピングを確認してください

今、新しいマップを確認してください。コードを更新することによりProgram.csMainする方法:

static void Main(string[] args)
{
    DateTime datetime1 = DateTime.Now;
    using (var context = new DynamicContext { CreateDateTime = datetime1 })
    {
        context.Entities.Add(new ConfigurableEntity { Title = "Great News One", Content = $"Hello World! I am the news of {datetime1}", CreateDateTime = datetime1 });
        context.SaveChanges();
    }
    DateTime datetime2 = DateTime.Now.AddDays(-1);
    using (var context = new DynamicContext { CreateDateTime = datetime2 })
    {
        context.Entities.Add(new ConfigurableEntity { Title = "Great News Two", Content = $"Hello World! I am the news of {datetime2}", CreateDateTime = datetime2 });
        context.SaveChanges();
    }

    using (var context = new DynamicContext { CreateDateTime = datetime1 })
    {
        var entity = context.Entities.Single();
          // Writes news of today
        Console.WriteLine($"{entity.Title} {entity.Content} {entity.CreateDateTime}");
    }

    using (var context = new DynamicContext { CreateDateTime = datetime2 })
    {
        var entity = context.Entities.Single();
        // Writes news of yesterday
        Console.WriteLine($"{entity.Title} {entity.Content} {entity.CreateDateTime}");
    }
}

あなたは、次の出力が表示されます。

今、私たちは、転送することができCreateDateTime、同じを使用するようにプロパティをDbContext異なるモデルを表現するために。

リリース6元記事 ウォン称賛19 ビュー10万+

おすすめ

転載: blog.csdn.net/lixiaoer757/article/details/105303868