次の方法で共有


モデルの一括構成

複数のエンティティ型で同じ方法で側面を構成する必要がある場合、次の手法を使用すると、コードの重複を減らし、ロジックを統合できます。

以下に示すコード スニペットを含む 完全なサンプル プロジェクト を参照してください。

OnModelCreating での一括構成

ModelBuilderから返されるすべてのビルダー オブジェクトは、モデルを構成するオブジェクトへの低レベルのアクセスを提供するModelまたはMetadataプロパティを公開します。 特に、モデル内の特定のオブジェクトを反復処理し、それらに共通の構成を適用できるメソッドがあります。

次の例では、モデルにカスタム値型 Currencyが含まれています。

public readonly struct Currency
{
    public Currency(decimal amount)
        => Amount = amount;

    public decimal Amount { get; }

    public override string ToString()
        => $"${Amount}";
}

現在の EF プロバイダーではデータベース型にマップする方法がわからないため、この型のプロパティは既定では検出されません。 この OnModelCreating スニペットは、 Currency 型のすべてのプロパティを追加し、サポートされている型に値コンバーターを構成します。 decimal

foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
    foreach (var propertyInfo in entityType.ClrType.GetProperties())
    {
        if (propertyInfo.PropertyType == typeof(Currency))
        {
            entityType.AddProperty(propertyInfo)
                .SetValueConverter(typeof(CurrencyConverter));
        }
    }
}
public class CurrencyConverter : ValueConverter<Currency, decimal>
{
    public CurrencyConverter()
        : base(
            v => v.Amount,
            v => new Currency(v))
    {
    }
}

メタデータ API の欠点

  • Fluent API とは異なり、モデルに対するすべての変更を明示的に行う必要があります。 たとえば、一部の Currency プロパティが規則によってナビゲーションとして構成されている場合は、まず CLR プロパティを参照するナビゲーションを削除してから、エンティティ型プロパティを追加する必要があります。 #9117 はこれを改善します。
  • 規則は、変更後に実行されます。 規則によって検出されたナビゲーションを削除すると、規則が再度実行され、再度追加される可能性があります。 この問題が発生しないようにするには、 DelayConventions() を呼び出してプロパティが追加されるまで規則を遅らせ、後で返されたオブジェクトを破棄するか、clr プロパティを無視済みとしてマークする必要 AddIgnored
  • このイテレーションが行われると、エンティティ型が追加される可能性があり、構成は適用されません。 これは通常、 OnModelCreatingの最後にこのコードを配置することで防ぐことができますが、2 つの相互に依存する構成セットがある場合は、一貫して適用できる順序がない可能性があります。

大会前の構成

EF Core では、特定の CLR 型に対してマッピング構成を 1 回指定できます。その構成は、検出されると、モデル内のその型のすべてのプロパティに適用されます。 これは、モデル構築規則の実行が許可される前にモデルの側面を構成するため、"事前規則モデル構成" と呼ばれます。 このような構成は、ConfigureConventionsから派生した型のDbContextをオーバーライドすることによって適用されます。

この例では、値コンバーターを持つ型 Currency のすべてのプロパティを構成する方法を示します。

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
    configurationBuilder
        .Properties<Currency>()
        .HaveConversion<CurrencyConverter>();
}

この例では、 string型のすべてのプロパティに対していくつかのファセットを構成する方法を示します。

configurationBuilder
    .Properties<string>()
    .AreUnicode(false)
    .HaveMaxLength(1024);

ConfigureConventionsからの呼び出しで指定される型には、基本型、インターフェイス、またはジェネリック型定義を指定できます。 一致するすべての構成は、最も具体的な順序で適用されます。

  1. インターフェイス
  2. 基本型
  3. ジェネリック型の定義
  4. 非null許容値型
  5. 正確な型

Von Bedeutung

事前規則の構成は、一致するオブジェクトがモデルに追加されるとすぐに適用される明示的な構成と同じです。 すべての規則とデータ注釈がオーバーライドされます。 たとえば、上記の構成では、プリンシパル キーと一致しない場合でも、すべての文字列外部キー プロパティが unicode 以外の MaxLength 1024 として作成されます。

型を無視する

事前規則の構成では、型を無視し、エンティティ型またはエンティティ型のプロパティとして規則によって検出されないようにすることもできます。

configurationBuilder
    .IgnoreAny(typeof(IList<>));

既定の型マッピング

一般に、EF は、この型のプロパティに値コンバーターを指定している限り、プロバイダーでサポートされていない型の定数を持つクエリを変換できます。 ただし、この型のプロパティを含まないクエリでは、EF が正しい値コンバーターを見つける方法はありません。 この場合、 DefaultTypeMapping を呼び出して、プロバイダーの型マッピングを追加またはオーバーライドすることができます。

configurationBuilder
    .DefaultTypeMapping<Currency>()
    .HasConversion<CurrencyConverter>();

規則前の構成の制限事項

  • この方法では、多くの側面を構成できません。 #6787 では、これをさらに多くの型に拡張します。
  • 現在、構成は CLR 型によってのみ決定されます。 #20418 では、カスタム述語を使用できます。
  • この構成は、モデルが作成される前に実行されます。 適用時に競合が発生した場合、例外スタック トレースには ConfigureConventions メソッドが含まれないため、原因を見つけるのが難しくなる可能性があります。

慣例

EF Core モデル構築規則は、ビルド中にモデルに加えられた変更に基づいてトリガーされるロジックを含むクラスです。 これにより、明示的な構成が行われ、マッピング属性が適用され、その他の規則が実行されるため、モデルは -date up-to保持されます。 これに参加するために、すべての規則は、対応するメソッドがいつトリガーされるかを決定する 1 つ以上のインターフェイスを実装します。 たとえば、 IEntityTypeAddedConvention を実装する規則は、新しいエンティティ型がモデルに追加されるたびにトリガーされます。 同様に、 IForeignKeyAddedConventionIKeyAddedConvention の両方を実装する規則は、キーまたは外部キーがモデルに追加されるたびにトリガーされます。

モデル構築規則は、モデル構成を制御するための強力な方法ですが、複雑で、正しく行きにくい場合があります。 多くの場合、事前 規則モデルの構成 を代わりに使用して、プロパティと型に共通の構成を簡単に指定できます。

新しい規則の追加

例: 識別子プロパティの長さを制限する

階層ごとのテーブル継承マッピング戦略では、特定の行で表される型を指定する識別子列が必要です。 既定では、EF は識別子にバインドされていない文字列列を使用します。これにより、識別子の長さに対して動作することが保証されます。 ただし、識別子文字列の最大長を制限すると、より効率的なストレージとクエリが可能になります。 これを行う新しい規則を作成しましょう。

EF Core モデル構築規則は、ビルド中にモデルに加えられた変更に基づいてトリガーされます。 これにより、明示的な構成が行われ、マッピング属性が適用され、その他の規則が実行されるため、モデルは -date up-to保持されます。 これに参加するために、すべての規則は、規則がトリガーされるタイミングを決定する 1 つ以上のインターフェイスを実装します。 たとえば、 IEntityTypeAddedConvention を実装する規則は、新しいエンティティ型がモデルに追加されるたびにトリガーされます。 同様に、 IForeignKeyAddedConventionIKeyAddedConvention の両方を実装する規則は、キーまたは外部キーがモデルに追加されるたびにトリガーされます。

ある時点でモデルに対して行われた構成は後で変更または削除される可能性があるため、実装するインターフェイスを把握するのは難しい場合があります。 たとえば、規則によってキーを作成できますが、後で別のキーが明示的に構成されると置き換えられます。

識別子の長さの規則を実装する最初の試みを行って、これをもう少し具体的にしましょう。

public class DiscriminatorLengthConvention1 : IEntityTypeBaseTypeChangedConvention
{
    public void ProcessEntityTypeBaseTypeChanged(
        IConventionEntityTypeBuilder entityTypeBuilder,
        IConventionEntityType? newBaseType,
        IConventionEntityType? oldBaseType,
        IConventionContext<IConventionEntityType> context)
    {
        var discriminatorProperty = entityTypeBuilder.Metadata.FindDiscriminatorProperty();
        if (discriminatorProperty != null
            && discriminatorProperty.ClrType == typeof(string))
        {
            discriminatorProperty.Builder.HasMaxLength(24);
        }
    }
}

この規則は、 IEntityTypeBaseTypeChangedConventionを実装します。つまり、エンティティ型のマップされた継承階層が変更されるたびにトリガーされます。 次に、この規則は、階層の文字列判別プロパティを検索して構成します。

この規則は、AddConfigureConventionsを呼び出すことによって使用されます。

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
    configurationBuilder.Conventions.Add(_ =>  new DiscriminatorLengthConvention1());
}

Add メソッドは、規則のインスタンスを直接追加するのではなく、規則のインスタンスを作成するためのファクトリを受け入れます。 これにより、慣例は EF Core の内部サービスプロバイダーからの依存関係を利用できます。 この規則には依存関係がないため、サービス プロバイダー パラメーターには _ という名前が付けられ、使用されていないことを示します。

モデルを構築し、 Post エンティティ型を調べることで、これが機能したことが示されています。識別子プロパティは、最大長が 24 に構成されるようになりました。

 Discriminator (no field, string) Shadow Required AfterSave:Throw MaxLength(24)

しかし、別の識別子プロパティを明示的に構成した場合はどうなりますか? 例えば次が挙げられます。

modelBuilder.Entity<Post>()
    .HasDiscriminator<string>("PostTypeDiscriminator")
    .HasValue<Post>("Post")
    .HasValue<FeaturedPost>("Featured");

モデルの デバッグ ビュー を見ると、識別子の長さが構成されなくなったことがわかります。

 PostTypeDiscriminator (no field, string) Shadow Required AfterSave:Throw

これは、この規則で構成した識別子プロパティは、カスタム識別子が追加されたときに後で削除されたためです。 これを修正するには、識別子の変更に対応する別のインターフェイスを規則に実装しますが、実装するインターフェイスを見つけ出すのは簡単ではありません。

幸いなことに、より簡単なアプローチがあります。 多くの場合、最終的なモデルが正しい限り、構築中のモデルの外観は関係ありません。 さらに、多くの場合、適用する構成では、他の規則をトリガーして対応する必要はありません。 したがって、この規則では IModelFinalizingConventionを実装できます。 モデルの最終決定規則 は、他のすべてのモデル構築が完了した後に実行されるため、モデルの最終状態に近い状態にアクセスできます。 これは、各モデルの変更に対応し、 メソッドの実行の任意の時点でモデルが up-to-date であることを確認するOnModelCreatingとは対照的です。 通常、モデルの最終化のための規約は、モデル要素を構成しながらモデル全体を反復処理します。 そのため、この場合、モデル内のすべての識別子を見つけて構成します。

public class DiscriminatorLengthConvention2 : IModelFinalizingConvention
{
    public void ProcessModelFinalizing(IConventionModelBuilder modelBuilder, IConventionContext<IConventionModelBuilder> context)
    {
        foreach (var entityType in modelBuilder.Metadata.GetEntityTypes()
                     .Where(entityType => entityType.BaseType == null))
        {
            var discriminatorProperty = entityType.FindDiscriminatorProperty();
            if (discriminatorProperty != null
                && discriminatorProperty.ClrType == typeof(string))
            {
                discriminatorProperty.Builder.HasMaxLength(24);
            }
        }
    }
}

この新しい規則を使用してモデルを構築した後、識別子の長さがカスタマイズされていても正しく構成されていることがわかります。

PostTypeDiscriminator (no field, string) Shadow Required AfterSave:Throw MaxLength(24)

さらに 1 ステップ進み、最大長を最長識別子値の長さとして構成できます。

public class DiscriminatorLengthConvention3 : IModelFinalizingConvention
{
    public void ProcessModelFinalizing(IConventionModelBuilder modelBuilder, IConventionContext<IConventionModelBuilder> context)
    {
        foreach (var entityType in modelBuilder.Metadata.GetEntityTypes()
                     .Where(entityType => entityType.BaseType == null))
        {
            var discriminatorProperty = entityType.FindDiscriminatorProperty();
            if (discriminatorProperty != null
                && discriminatorProperty.ClrType == typeof(string))
            {
                var maxDiscriminatorValueLength =
                    entityType.GetDerivedTypesInclusive().Select(e => ((string)e.GetDiscriminatorValue()!).Length).Max();

                discriminatorProperty.Builder.HasMaxLength(maxDiscriminatorValueLength);
            }
        }
    }
}

識別子列の最大長は 8 になり、"Featured" の長さ (使用中の最も長い識別子の値) になります。

PostTypeDiscriminator (no field, string) Shadow Required AfterSave:Throw MaxLength(8)

例: すべての文字列プロパティの既定の長さ

終了規則を使用できる別の例を見てみましょう。 任意 の文字列プロパティの既定の最大長を設定します。 この規則は、前の例によく似ています。

public class MaxStringLengthConvention : IModelFinalizingConvention
{
    public void ProcessModelFinalizing(IConventionModelBuilder modelBuilder, IConventionContext<IConventionModelBuilder> context)
    {
        foreach (var property in modelBuilder.Metadata.GetEntityTypes()
                     .SelectMany(
                         entityType => entityType.GetDeclaredProperties()
                             .Where(
                                 property => property.ClrType == typeof(string))))
        {
            property.Builder.HasMaxLength(512);
        }
    }
}

この規則は非常に単純です。 モデル内のすべての文字列プロパティを検索し、その最大長を 512 に設定します。 Postのプロパティのデバッグ ビューを見ると、すべての文字列プロパティの最大長が 512 になっていることがわかります。

EntityType: Post
  Properties:
    Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd
    AuthorId (no field, int?) Shadow FK Index
    BlogId (no field, int) Shadow Required FK Index
    Content (string) Required MaxLength(512)
    Discriminator (no field, string) Shadow Required AfterSave:Throw MaxLength(512)
    PublishedOn (DateTime) Required
    Title (string) Required MaxLength(512)

事前規則の構成でも同じことができますが、規則を使用すると、適用可能なプロパティをさらにフィルター処理したり、 データ注釈で構成をオーバーライドしたりできます。

最後に、この例を終了する前に、 MaxStringLengthConventionDiscriminatorLengthConvention3 の両方を同時に使用するとどうなりますか? 答えは、モデルの最終決定規則は追加された順序で実行されるため、追加される順序によって異なります。 したがって、 MaxStringLengthConvention が最後に追加されると、最後に実行され、識別子プロパティの最大長が 512 に設定されます。 したがって、この場合は、最後 DiscriminatorLengthConvention3 追加して、識別子プロパティの既定の最大長をオーバーライドできるようにし、他のすべての文字列プロパティは 512 のままにすることをお勧めします。

既存の規則を置き換える

場合によっては、既存の規則を完全に削除するのではなく、基本的に同じことを行うが動作が変更された規則に置き換える必要があります。 これは、既存の規則によって、適切にトリガーする必要があるインターフェイスが既に実装されるため便利です。

例: オプトイン プロパティマッピング

EF Core は、規則によってすべてのパブリック読み取り/書き込みプロパティをマップします。 これは、エンティティ型の定義方法には適さない場合があります。 これを変更するには、PropertyDiscoveryConventionで明示的にマップされていないか、OnModelCreatingという新しい属性でマークされていない限り、プロパティをマップしない独自の実装でPersistを置き換えることができます。

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public sealed class PersistAttribute : Attribute
{
}

新しい規則を次に示します。

public class AttributeBasedPropertyDiscoveryConvention : PropertyDiscoveryConvention
{
    public AttributeBasedPropertyDiscoveryConvention(ProviderConventionSetBuilderDependencies dependencies)
        : base(dependencies)
    {
    }

    public override void ProcessEntityTypeAdded(
        IConventionEntityTypeBuilder entityTypeBuilder,
        IConventionContext<IConventionEntityTypeBuilder> context)
        => Process(entityTypeBuilder);

    public override void ProcessEntityTypeBaseTypeChanged(
        IConventionEntityTypeBuilder entityTypeBuilder,
        IConventionEntityType? newBaseType,
        IConventionEntityType? oldBaseType,
        IConventionContext<IConventionEntityType> context)
    {
        if ((newBaseType == null
             || oldBaseType != null)
            && entityTypeBuilder.Metadata.BaseType == newBaseType)
        {
            Process(entityTypeBuilder);
        }
    }

    private void Process(IConventionEntityTypeBuilder entityTypeBuilder)
    {
        foreach (var memberInfo in GetRuntimeMembers())
        {
            if (Attribute.IsDefined(memberInfo, typeof(PersistAttribute), inherit: true))
            {
                entityTypeBuilder.Property(memberInfo);
            }
            else if (memberInfo is PropertyInfo propertyInfo
                     && Dependencies.TypeMappingSource.FindMapping(propertyInfo) != null)
            {
                entityTypeBuilder.Ignore(propertyInfo.Name);
            }
        }

        IEnumerable<MemberInfo> GetRuntimeMembers()
        {
            var clrType = entityTypeBuilder.Metadata.ClrType;

            foreach (var property in clrType.GetRuntimeProperties()
                         .Where(p => p.GetMethod != null && !p.GetMethod.IsStatic))
            {
                yield return property;
            }

            foreach (var property in clrType.GetRuntimeFields())
            {
                yield return property;
            }
        }
    }
}

ヒント

組み込み規則を置き換える場合、新しい規則の実装は既存の規則クラスから継承する必要があります。 一部の規則にはリレーショナルまたはプロバイダー固有の実装があります。この場合、新しい規則の実装は、使用中のデータベース プロバイダーの最も具体的な既存の規則クラスから継承する必要があります。

この規則は、ReplaceConfigureConventions メソッドを使用して登録されます。

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
    configurationBuilder.Conventions.Replace<PropertyDiscoveryConvention>(
        serviceProvider => new AttributeBasedPropertyDiscoveryConvention(
            serviceProvider.GetRequiredService<ProviderConventionSetBuilderDependencies>()));
}

ヒント

これは、既存の規則に依存関係があり、 ProviderConventionSetBuilderDependencies 依存関係オブジェクトによって表される場合です。 これらは、 GetRequiredService を使用して内部サービス プロバイダーから取得され、規約コンストラクターに渡されます。

この規則では、フィールドが [Persist] でマークされている限り、フィールドを (プロパティに加えて) マップできます。 つまり、モデルでは秘密フィールドを非表示キーとして使用できます。

たとえば、次のエンティティ型を考えてみましょう。

public class LaundryBasket
{
    [Persist]
    [Key]
    private readonly int _id;

    [Persist]
    public int TenantId { get; init; }

    public bool IsClean { get; set; }

    public List<Garment> Garments { get; } = new();
}

public class Garment
{
    public Garment(string name, string color)
    {
        Name = name;
        Color = color;
    }

    [Persist]
    [Key]
    private readonly int _id;

    [Persist]
    public int TenantId { get; init; }

    [Persist]
    public string Name { get; }

    [Persist]
    public string Color { get; }

    public bool IsClean { get; set; }

    public LaundryBasket? Basket { get; set; }
}

これらのエンティティ型から構築されたモデルは次のとおりです。

Model:
  EntityType: Garment
    Properties:
      _id (_id, int) Required PK AfterSave:Throw ValueGenerated.OnAdd
      Basket_id (no field, int?) Shadow FK Index
      Color (string) Required
      Name (string) Required
      TenantId (int) Required
    Navigations:
      Basket (LaundryBasket) ToPrincipal LaundryBasket Inverse: Garments
    Keys:
      _id PK
    Foreign keys:
      Garment {'Basket_id'} -> LaundryBasket {'_id'} ToDependent: Garments ToPrincipal: Basket ClientSetNull
    Indexes:
      Basket_id
  EntityType: LaundryBasket
    Properties:
      _id (_id, int) Required PK AfterSave:Throw ValueGenerated.OnAdd
      TenantId (int) Required
    Navigations:
      Garments (List<Garment>) Collection ToDependent Garment Inverse: Basket
    Keys:
      _id PK

通常、 IsClean はマップされていますが、 [Persist]でマークされていないため、マップされていないプロパティとして扱われるようになりました。

ヒント

プロパティをさらに構成するためにマップした後に実行する必要がある既存のモデルファイナライズ規則があるため、この規則をモデルの最終処理規則として実装できませんでした。

規則の実装に関する考慮事項

EF Core では、すべての構成がどのように行われたかを追跡します。 これは、 ConfigurationSource 列挙型によって表されます。 構成の種類は次のとおりです。

  • Explicit: モデル要素はOnModelCreatingで明示的に構成されました
  • DataAnnotation: モデル要素は、CLR 型のマッピング属性 (別名データ注釈) を使用して構成されました
  • Convention: モデル要素は、モデル構築規則によって構成されました

規則は、 DataAnnotation または Explicitとしてマークされた構成をオーバーライドしないでください。 これは、 プロパティから取得されるIConventionPropertyBuilderなどのBuilderを使用して実現されます。 例えば次が挙げられます。

property.Builder.HasMaxLength(512);

規則ビルダーでHasMaxLengthを呼び出すと、マッピング属性またはOnModelCreatingでまだ構成されていない場合にのみ、最大長が設定されます。

このようなビルダー メソッドには、2 つ目のパラメーター ( fromDataAnnotation) もあります。 規則がマッピング属性に代わって構成を行っている場合は、これを true に設定します。 例えば次が挙げられます。

property.Builder.HasMaxLength(512, fromDataAnnotation: true);

これにより、 ConfigurationSourceDataAnnotationに設定されます。つまり、 OnModelCreatingでの明示的なマッピングによって値をオーバーライドできますが、非マッピング属性規則ではオーバーライドできません。

現在の構成をオーバーライドできない場合、メソッドは nullを返します。さらに構成を実行する必要がある場合は、これを考慮する必要があります。

property.Builder.HasMaxLength(512)?.IsUnicode(false);

Unicode 構成をオーバーライドできない場合でも、最大長が設定されることに注意してください。 両方の呼び出しが成功した場合にのみファセットを構成する必要がある場合は、 CanSetMaxLengthCanSetIsUnicodeを呼び出すことによって先制的にこれを確認できます。

public class MaxStringLengthNonUnicodeConvention : IModelFinalizingConvention
{
    public void ProcessModelFinalizing(IConventionModelBuilder modelBuilder, IConventionContext<IConventionModelBuilder> context)
    {
        foreach (var property in modelBuilder.Metadata.GetEntityTypes()
                     .SelectMany(
                         entityType => entityType.GetDeclaredProperties()
                             .Where(
                                 property => property.ClrType == typeof(string))))
        {
            var propertyBuilder = property.Builder;
            if (propertyBuilder.CanSetMaxLength(512)
                && propertyBuilder.CanSetIsUnicode(false))
            {
                propertyBuilder.HasMaxLength(512)!.IsUnicode(false);
            }
        }
    }
}

ここでは、 HasMaxLength の呼び出しが null返されないことを確認できます。 HasMaxLengthから返されるビルダー インスタンスは、propertyBuilderとは異なる場合があるため、引き続き使用することをお勧めします。

その他の規則は、規則が変更を行った直後にはトリガーされず、すべての規則が現在の変更の処理を完了するまで遅延されます。

IConventionContext

すべての規則メソッドには、 IConventionContext<TMetadata> パラメーターもあります。 特定の場合に役立つ可能性のあるメソッドが提供されます。

例: NotMappedAttribute 規則

この規則では、モデルに追加された型の NotMappedAttribute を検索し、そのエンティティ型をモデルから削除しようとします。 ただし、エンティティ型がモデルから削除された場合、 ProcessEntityTypeAdded を実装する他の規則を実行する必要はなくなります。 これを行うには、 StopProcessing()を呼び出します。

public virtual void ProcessEntityTypeAdded(
    IConventionEntityTypeBuilder entityTypeBuilder,
    IConventionContext<IConventionEntityTypeBuilder> context)
{
    var type = entityTypeBuilder.Metadata.ClrType;
    if (!Attribute.IsDefined(type, typeof(NotMappedAttribute), inherit: true))
    {
        return;
    }

    if (entityTypeBuilder.ModelBuilder.Ignore(entityTypeBuilder.Metadata.Name, fromDataAnnotation: true) != null)
    {
        context.StopProcessing();
    }
}

IConventionModel

規則に渡されるすべてのビルダー オブジェクトは、モデルを構成するオブジェクトへの低レベルのアクセスを提供する Metadata プロパティを公開します。 具体的には、「 例: すべての文字列プロパティの既定の長さ」に示すように、モデル内の特定のオブジェクトを反復処理し、それらに共通の構成を適用できるメソッドがあります。 この API は、IMutableModelに示されているに似ています。

注意事項

ビルダーは、指定された構成が Fluent API またはデータ注釈を使用して既に指定されたものをオーバーライドするかどうかをチェックするため、 Builder プロパティとして公開されているビルダーでメソッドを呼び出すことによって、常に構成を実行することをお勧めします。

一括構成に各アプローチを使用する場合

メタデータ API は、次の場合に使用します。

  • 構成は特定の時点で適用する必要があり、モデルの後の変更には対応しない必要があります。
  • モデルの構築速度は非常に重要です。 メタデータ API の安全性チェックが少なくなるため、他の方法よりも若干高速になる場合があります。ただし、 コンパイル済みモデル を使用すると、起動時間がさらに短縮されます。

次の場合は、事前規則モデルの構成を使用します。

  • 適用条件は型によってのみ異なるため、単純です。
  • 構成は、特定の型のプロパティがモデルに追加され、データ注釈と規則をオーバーライドする任意の時点で適用する必要があります

次のような場合に最終処理規則を使用します

  • 適用条件は複雑です。
  • 構成は、データ注釈で指定されているものをオーバーライドしないでください。

対話型の規則は、次の場合に使用します

  • 複数の規則は互いに依存します。 ファイナライズ規則は追加された順序で実行されるため、後で規則を最終処理することによって行われた変更には対応できません。
  • ロジックは、複数のコンテキスト間で共有されます。 対話型の規則は、他の方法よりも安全です。