次のようなクラスが1つあるとします。
public class Entity
{
public IList<string> SomeListOfValues { get; set; }
// Other code
}
ここで、EF Core Code Firstを使用してこれを維持し、SQL ServerのようなRDMBSを使用しているとします。
考えられるアプローチの1つは、明らかに、文字列をラップするラッパークラスWraper
を作成することです。
public class Wraper
{
public int Id { get; set; }
public string Value { get; set; }
}
クラスをリファクタリングして、 Wraper
オブジェクトのリストに依存するようにします。その場合、EFはWraper
テーブルであるEntity
テーブルを生成し、「1対多数」の関係を確立します。各エンティティには複数のラッパーがあります。
これは機能しますが、永続性の懸念から非常に単純なモデルを変更しているため、私はアプローチがあまり好きではありません。確かに、永続性のないドメインモデルとコードについて考えてWraper
と、 Wraper
クラスはそこでは意味がありません。
ラッパークラスを作成する以外に、EFコアコードを使用してRDBMSに文字列のリストを持つ1つのエンティティを永続させる他の方法はありますか?もちろん、最終的には同じことが行われなければなりません。文字列を保持するために別のテーブルを作成しなければならず、「一対多の」関係が必要です。私はちょうどドメインモデルでラッパークラスをコードする必要なくEFコアでこれをしたいです。
これは、Entity Framework Core 2.1以降では、はるかに簡単な方法で実現できます。 EFは、プロパティを格納のために別のタイプにマッピングする必要があるという、このようなシナリオに特に対処するための値変換をサポートします。
文字列のコレクションを永続化するには、次のようにDbContext
を設定します。
protected override void OnModelCreating(ModelBuilder builder)
{
var splitStringConverter = new ValueConverter<IEnumerable<string>, string>(v => string.Join(";", v), v => v.Split(new[] { ';' }));
builder.Entity<Entity>().Property(nameof(Entity.SomeListOfValues)).HasConversion(splitStringConverter);
}
このソリューションでは、DBの問題であなたのビジネスクラスが悩むことはありません。
言うまでもなく、この解決方法では、文字列に区切り文字を含めることができないようにする必要があります。しかしもちろん、カスタムのロジックを使って変換を行うこともできます(例:JSONから/への変換)。
もう1つの興味深い事実は、NULL値は変換ルーチンに渡されず 、フレームワーク自体によって処理されることです。したがって、nullチェックについて心配する必要はありません。