読者です 読者をやめる 読者になる 読者になる

yamamoWorks

.NET技術を中心に気まぐれに更新していきます

DbContextを動的に使用する

.NET EntityFramework Tips

今回はEntity FrameworkのDbContextを動的に使おうというお話です。

Entity Frameworkを普通に使う時はDbContextを継承したクラスにDbSet<モデルクラス>なプロパティを実装しますよね。

public class AddressBookContext : DbContext
{
public AddressBookContext()
: base("AddressBookContext")
{
}

public DbSet Persons { get; set; }
}
では、モデルクラスが実行時に決まる場合はどうすればよいか?

実行時にDbModelBuilder.Entity()メソッドを呼んでやりましょう。
public class DynamicDbContext : DbContext
{
private static readonly MethodInfo DbModelBuilderEntityMethod;

static DynamicDbContext()
{
// DbModelBuilder.Entity
() を取得
DbModelBuilderEntityMethod = typeof(DbModelBuilder).GetMethod("Entity");
}

public DynamicDbContext(string nameOrConnectionString, params Type entityTypes)
: base(nameOrConnectionString)
{
this.EntityTypes = entityTypes;
}

public Type
EntityTypes { get; private set; }

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
foreach (var entityType in EntityTypes)
{
// DbModelBuilder.Entity() を実行
_DbModelBuilderEntityMethod.MakeGenericMethod(entityType).Invoke(modelBuilder, new object[] { });
}
}
}DbContextはインスタンスを生成する際の内部処理で、自身に実装されているDbSet
なプロパティを探しDbModelBuilder.Entity()メソッドを実行しています。
なのでOnModelCreatingをオーバーライドして任意のモデルクラスでDbModelBuilder.Entity
()メソッドを実行すればDbSetなプロパティを定義しなくともモデルクラスがエンティティとして登録されます。

使い方
// 実行時に型が判明したとする
var newEntities = new[]
{
new Person { FirstName = "Naida", LastName="Huber" },
new Person { FirstName = "Miriam", LastName="Dickson" },
new Person { FirstName = "Jermaine", LastName="Martin" },
};

var type = newEntities.GetType().GetElementType();

using (var db = new DynamicDbContext("DynamicDbContext", type))
{
// DbSet
プロパティは無いのでSet()メソッドでDbSetインスタンスを取得
var dbSet = db.Set(type);

Console.WriteLine(dbSet.ElementType); // --> Person

dbSet.AddRange(newEntities);
db.SaveChanges();
}
で、これ何が嬉しいのか?

Entity Frameworkはデータベースにテーブルを作成してくれるので、一時的にデータを格納したい場合とか(謎)

定義された型(上例だとPersonクラス)ではなく動的に生成した型と組み合わせると活きてきます。