Model toplu yapılandırması

Bir yönün birden çok varlık türünde aynı şekilde yapılandırılması gerektiğinde, aşağıdaki teknikler kod yinelemesini azaltmaya ve mantığı birleştirmeye olanak sağlar.

Aşağıda sunulan kod parçacıklarını içeren tam örnek projeye bakın.

OnModelCreating'de toplu yapılandırma

öğesinden ModelBuilder döndürülen her oluşturucu nesnesi, modeli oluşturan nesnelere alt düzey erişim sağlayan bir Model veya Metadata özelliğini kullanıma sunar. Özellikle, modeldeki belirli nesneler üzerinde yineleme yapmanızı ve bunlara ortak yapılandırma uygulamanızı sağlayan yöntemler vardır.

Aşağıdaki örnekte model özel bir değer türü Currencyiçerir:

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

    public decimal Amount { get; }

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

Geçerli EF sağlayıcısı bunu bir veritabanı türüyle eşlemeyi bilmediğinden, bu türün özellikleri varsayılan olarak bulunmaz. Bu kod parçacığı türün OnModelCreatingCurrency tüm özelliklerini ekler ve desteklenen bir türe bir değer dönüştürücüsü yapılandırılır - 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))
    {
    }
}

Meta Veri API'sinin dezavantajları

  • Fluent API'sinin aksine modelde yapılan her değişikliğin açıkça yapılması gerekir. Örneğin, bazı Currency özellikler bir kural tarafından gezinti olarak yapılandırıldıysa, bir varlık türü özelliği eklemeden önce CLR özelliğine başvuran gezintiyi kaldırmanız gerekir. #9117 bunu geliştirecektir.
  • Kurallar her değişiklik sonrasında çalışır. Bir kural tarafından bulunan bir gezintiyi kaldırırsanız, kural yeniden çalışır ve bunu geri ekleyebilir. Bunun olmasını önlemek için çağrılarak özellik eklenene DelayConventions() kadar kuralları geciktirip döndürülen nesneyi daha sonra yok saymanız veya kullanarak AddIgnoredCLR özelliğini yoksayıldı olarak işaretlemeniz gerekir.
  • Bu yineleme gerçekleştirildikten sonra varlık türleri eklenebilir ve yapılandırma bunlara uygulanmaz. Bu durum genellikle bu kodu sonuna OnModelCreatingyerleştirerek önlenebilir, ancak birbirine bağlı iki yapılandırma kümeniz varsa, bunların tutarlı bir şekilde uygulanmasına izin verecek bir sıra olmayabilir.

Kural öncesi yapılandırma

EF Core, belirli bir CLR türü için eşleme yapılandırmasının bir kez belirtilmesine izin verir; bu yapılandırma daha sonra modelde bulunan bu türdeki tüm özelliklere uygulanır. Model oluşturma kurallarının çalışmasına izin verilmeden önce modelin yönlerini yapılandırdığından buna "kural öncesi model yapılandırması" denir. Bu tür yapılandırma, türünden DbContexttüretilen geçersiz kılınarak ConfigureConventions uygulanır.

Bu örnekte, türün Currency tüm özelliklerinin bir değer dönüştürücüsü olacak şekilde nasıl yapılandırılır gösterilmektedir:

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

Ve bu örnekte, türündeki stringtüm özelliklerde bazı modellerin nasıl yapılandırılır gösterilmektedir:

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

Dekont

çağrısında ConfigureConventions belirtilen tür bir temel tür, arabirim veya genel tür tanımı olabilir. Tüm eşleşen yapılandırmalar en az belirli bir sırayla uygulanır:

  1. Arabirim
  2. Temel tür
  3. Genel tür tanımı
  4. Null değer atanamayan değer türü
  5. Tam tür

Önemli

Kural öncesi yapılandırma, modele eşleşen bir nesne eklendiğinde uygulanan açık yapılandırmaya eşdeğerdir. Tüm kuralları ve Veri Ek Açıklamalarını geçersiz kılar. Örneğin, yukarıdaki yapılandırmayla tüm dize yabancı anahtar özellikleri, asıl anahtarla MaxLength eşleşmese bile 1024 ile unicode olmayan olarak oluşturulur.

Türleri yoksayma

Kural öncesi yapılandırma ayrıca bir türü yoksaymaya ve bir varlık türü olarak veya bir varlık türünde özellik olarak kurallar tarafından bulunmasını önlemeye olanak tanır:

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

Varsayılan tür eşlemesi

Genel olarak, bu tür bir özellik için bir değer dönüştürücü belirttiğiniz sürece EF, sağlayıcı tarafından desteklenmeyen bir türdeki sabitlere sahip sorguları çevirebilir. Ancak, bu tür özellikleri içermeyen sorgularda EF'nin doğru değer dönüştürücüsünün bulunmasına imkan yoktur. Bu durumda, sağlayıcı türü eşlemesi eklemek veya geçersiz kılmak için çağrısı DefaultTypeMapping yapmak mümkündür:

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

Kural öncesi yapılandırma sınırlamaları

  • Bu yaklaşımla birçok özellik yapılandırılamaz. #6787 bunu daha fazla türe genişletir.
  • Şu anda yapılandırma yalnızca CLR türü tarafından belirlenir. #20418 özel koşula izin verir.
  • Bu yapılandırma, bir model oluşturulmadan önce gerçekleştirilir. Uygulama sırasında ortaya çıkan çakışmalar varsa, özel durum yığını izleme yöntemi içermez ConfigureConventions , bu nedenle nedenini bulmak daha zor olabilir.

Kurallar

Dekont

Ef Core 7.0'da özel model oluşturma kuralları kullanıma sunulmuştur.

EF Core model oluşturma kuralları, model oluşturulurken modelde yapılan değişikliklere göre tetiklenen mantığı içeren sınıflardır. Bu, açık yapılandırma yapıldıkçe, eşleme öznitelikleri uygulandıkça ve diğer kurallar çalıştırıldığında modelin güncel kalmasını sağlar. Buna katılmak için her kural, ilgili yöntemin ne zaman tetikleneceğini belirleyen bir veya daha fazla arabirim uygular. Örneğin, modele yeni bir varlık türü eklendiğinde uygulayan IEntityTypeAddedConvention bir kural tetiklenir. Benzer şekilde, hem uygulayan hem IKeyAddedConvention de IForeignKeyAddedConvention modele bir anahtar veya yabancı anahtar eklendiğinde tetiklenen bir kural.

Model oluşturma kuralları, model yapılandırmasını denetlemenin güçlü bir yoludur, ancak karmaşık ve düzeltilmesi zor olabilir. Çoğu durumda, özellikler ve türler için ortak yapılandırmayı kolayca belirtmek için kural öncesi model yapılandırması kullanılabilir.

Yeni kural ekleme

Örnek: Ayrımcı özelliklerin kısıt uzunluğu

Hiyerarşi başına tablo devralma eşleme stratejisi , belirli bir satırda hangi türün gösterileceğini belirtmek için ayrıştırıcı sütun gerektirir. Varsayılan olarak, EF ayırıcı için herhangi bir ayrımcı uzunluğu için çalışmasını sağlayan ilişkisiz bir dize sütunu kullanır. Ancak, ayrımcı dizelerin uzunluk üst sınırının kısıtlanması, depolama ve sorguların daha verimli olmasını sağlayabilir. Şimdi bunu yapacak yeni bir kural oluşturalım.

EF Core model oluşturma kuralları, model oluşturulurken modelde yapılan değişikliklere bağlı olarak tetiklenir. Bu, açık yapılandırma yapıldıkçe, eşleme öznitelikleri uygulandıkça ve diğer kurallar çalıştırıldığında modelin güncel kalmasını sağlar. Buna katılmak için her kural, kuralın ne zaman tetikleneceğini belirleyen bir veya daha fazla arabirim uygular. Örneğin, modele yeni bir varlık türü eklendiğinde uygulayan IEntityTypeAddedConvention bir kural tetiklenir. Benzer şekilde, hem uygulayan hem IKeyAddedConvention de IForeignKeyAddedConvention modele bir anahtar veya yabancı anahtar eklendiğinde tetiklenen bir kural.

Modele bir noktada yapılan yapılandırma daha sonraki bir noktada değiştirilebileceği veya kaldırılabildiği için uygulanacak arabirimleri bilmek karmaşık olabilir. Örneğin, bir anahtar kural tarafından oluşturulabilir, ancak daha sonra farklı bir anahtar açıkça yapılandırıldığında değiştirilir.

Ayırıcı uzunluk kuralını uygulamaya yönelik ilk denemeyi yaparak bunu biraz daha somut hale getirelim:

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);
        }
    }
}

Bu kural, bir varlık türü için eşlenmiş devralma hiyerarşisi her değiştirildiğinde tetikleneceği anlamına gelen öğesini uygular IEntityTypeBaseTypeChangedConvention. Kural daha sonra hiyerarşi için dize ayırıcı özelliğini bulur ve yapılandırılır.

Bu kural daha sonra içinde ConfigureConventionsçağrılarak Add kullanılır:

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

Dekont

yöntemi, kuralın bir örneğini doğrudan eklemek yerine kuralın Add örneklerini oluşturmak için bir fabrikayı kabul eder. Bu, kuralın EF Core iç hizmet sağlayıcısından bağımlılıkları kullanmasına olanak tanır. Bu kuralın bağımlılıkları olmadığından, hizmet sağlayıcısı parametresi hiçbir zaman kullanılmadığını belirten olarak adlandırılır _.

Modeli oluşturmak ve varlık türüne Post bakmak, bunun işe yaradığını gösterir; ayırıcı özelliği artık en fazla 24 uzunlukla yapılandırılır:

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

Ancak şimdi açıkça farklı bir ayrımcı özelliği yapılandırırsak ne olur? Örnek:

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

Modelin hata ayıklama görünümüne baktığımızda, ayrıştırıcı uzunluğunun artık yapılandırılmadığını tespit ediyoruz.

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

Bunun nedeni, kuralımızda yapılandırdığımız ayırıcı özelliğinin daha sonra özel ayrıştırıcı eklendiğinde kaldırılmış olmasıdır. Ayrıştırıcı değişikliklere tepki vermek için kuralımızda başka bir arabirim uygulayarak bunu düzeltmeye çalışabiliriz, ancak hangi arabirimi uygulayacağımızı bulmak kolay değildir.

Neyse ki daha kolay bir yaklaşım var. Çoğu zaman, son model doğru olduğu sürece modelin oluşturulurken nasıl göründüğü önemli değildir. Buna ek olarak, uygulamak istediğimiz yapılandırmanın genellikle tepki vermek için başka kuralları tetiklemesi gerekmez. Bu nedenle, kuralımız uygulamasını uygulayabilir IModelFinalizingConvention. Model sonlandırma kuralları , diğer tüm model oluşturma işlemleri tamamlandıktan sonra çalıştırılır ve bu nedenle modelin neredeyse son durumuna erişebilirsiniz. Bu, her model değişikliğine tepki veren ve yöntem yürütmenin herhangi bir noktasında modelin güncel olduğundan emin olan etkileşimli kurallarınOnModelCreating aksinedir. Model sonlandırma kuralı genellikle model öğelerini yapılandıran modelin tamamı üzerinde yinelenir. Bu durumda modeldeki tüm ayrımcıları bulup yapılandıracağız:

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);
            }
        }
    }
}

Modeli bu yeni kuralla derledikten sonra, ayrıştırıcı uzunluğunun özelleştirildiği halde doğru yapılandırıldığını fark ettik:

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

Bir adım ileri gidebilir ve maksimum uzunluğu en uzun ayırıcı değerin uzunluğu olacak şekilde yapılandırabiliriz:

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);
            }
        }
    }
}

Artık en uzun ayırıcı sütun uzunluğu 8'dir ve bu da kullanımdaki en uzun ayrıştırıcı değeri olan "Öne Çıkan" uzunluğudur.

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

Örnek: Tüm dize özellikleri için varsayılan uzunluk

Bir sonlandırma kuralının kullanılabildiği başka bir örneğe bakalım: Herhangi bir dize özelliği için varsayılan maksimum uzunluk ayarlama. Kural önceki örneğe oldukça benzer:

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);
        }
    }
}

Bu kural oldukça basittir. Modeldeki her dize özelliğini bulur ve maksimum uzunluğunu 512 olarak ayarlar. özelliklerinde Posthata ayıklama görünümüne baktığımızda, tüm dize özelliklerinin artık en fazla 512 uzunluğuna sahip olduğunu görüyoruz.

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)

Dekont

Aynı işlem, kural öncesi yapılandırmayla da gerçekleştirilebilir, ancak kural kullanılması, geçerli özelliklerin daha fazla filtrelenmesine ve Veri Ek Açıklamalarının yapılandırmayı geçersiz kılmasına olanak tanır.

Son olarak, bu örnekten MaxStringLengthConvention ayrılmadan önce hem hem DiscriminatorLengthConvention3 de aynı anda kullanırsak ne olur? Bunun yanıtı, model sonlandırma kuralları eklendikleri sırayla çalıştırıldığından, bunların hangi sırayla eklendiğine bağlıdır. Bu nedenle, en son eklenirse MaxStringLengthConvention , en son çalışır ve ayırıcı özelliğinin maksimum uzunluğunu 512 olarak ayarlar. Bu nedenle, bu durumda, diğer tüm dize özelliklerini 512 olarak bırakırken yalnızca ayırıcı özellikleri için varsayılan maksimum uzunluğu geçersiz kılabilmesi için last eklemek DiscriminatorLengthConvention3 daha iyidir.

Mevcut bir kuralı değiştirme

Bazen mevcut bir kuralı tamamen kaldırmak yerine temelde aynı şeyi ancak değişen davranışı olan bir kuralla değiştirmek istiyoruz. Mevcut kural zaten uygun şekilde tetiklenmesi gereken arabirimleri uygulayacağından bu yararlı olur.

Örnek: Özellik eşlemeyi kabul etme

EF Core, tüm genel okuma-yazma özelliklerini kurala göre eşler. Bu, varlık türlerinizin tanımlanma biçimi için uygun olmayabilir. Bunu değiştirmek için, açıkça ile eşlenmediği OnModelCreating veya adlı Persistyeni bir öznitelikle işaretlenmediği sürece öğesini herhangi bir özelliği eşlemeyen kendi uygulamamızla değiştirebilirizPropertyDiscoveryConvention:

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

Yeni kural şu şekildedir:

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;
            }
        }
    }
}

Bahşiş

Yerleşik bir kuralı değiştirirken, yeni kural uygulaması mevcut kural sınıfından devralmalıdır. Bazı kuralların ilişkisel veya sağlayıcıya özgü uygulamaları olduğunu unutmayın. Bu durumda, yeni kural uygulaması kullanımdaki veritabanı sağlayıcısı için en belirli mevcut kural sınıfından devralmalıdır.

Kural daha sonra içindeki ConfigureConventionsyöntemi kullanılarak Replace kaydedilir:

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

Bahşiş

Bu durum, mevcut kuralın bağımlılık nesnesiyle ProviderConventionSetBuilderDependencies temsil edilen bağımlılıklara sahip olduğu bir durumdur. Bunlar kullanılarak GetRequiredService iç hizmet sağlayıcısından alınır ve kural oluşturucusna geçirilir.

Bu kuralın, ile [Persist]işaretlendikleri sürece alanların eşlenmesine (özelliklere ek olarak) izin verdiğine dikkat edin. Bu, özel alanları modelde gizli anahtarlar olarak kullanabileceğimiz anlamına gelir.

Örneğin, aşağıdaki varlık türlerini göz önünde bulundurun:

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; }
}

Bu varlık türlerinden oluşturulan model:

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

Normalde IsClean eşlenirdi, ancak ile [Persist]işaretlenmediğinden artık eşlenmemiş bir özellik olarak değerlendirilir.

Bahşiş

Özellik daha fazla yapılandırmak için eşlendikten sonra çalıştırılması gereken mevcut model sonlandırma kuralları olduğundan, bu kural model sonlandırma kuralı olarak uygulanamadı.

Kurallar uygulamasıyla ilgili dikkat edilmesi gerekenler

EF Core, her yapılandırma parçasının nasıl yapıldığını izler. Bu, sabit listesi tarafından ConfigurationSource temsil edilir. Farklı yapılandırma türleri şunlardır:

  • Explicit: Model öğesi açıkça içinde yapılandırıldı OnModelCreating
  • DataAnnotation: Model öğesi CLR türünde eşleme özniteliği (veri ek açıklaması) kullanılarak yapılandırıldı
  • Convention: Model öğesi bir model oluşturma kuralı tarafından yapılandırıldı

Kurallar, veya Explicitolarak DataAnnotation işaretlenmiş yapılandırmayı hiçbir zaman geçersiz kılmamalıdır. Bu, bir kural oluşturucu kullanılarak, örneğin özelliğinden IConventionPropertyBuilderBuilder elde edilen kullanılarak elde edilir. Örnek:

property.Builder.HasMaxLength(512);

Kural oluşturucusunda çağrılmasıHasMaxLength, yalnızca bir eşleme özniteliği tarafından veya içinde OnModelCreatingyapılandırılmamışsa maksimum uzunluğu ayarlar.

Bunun gibi oluşturucu yöntemlerinin ikinci bir parametresi de vardır: fromDataAnnotation. Kural bir eşleme özniteliği adına yapılandırma yapıyorsa bunu true olarak ayarlayın. Örnek:

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

Bu, değerini olarak ConfigurationSourceDataAnnotationayarlar. Bu, değerin artık üzerinde OnModelCreatingaçık eşleme yoluyla geçersiz kılınabileceği, ancak eşleme dışı öznitelik kuralları tarafından geçersiz kılınabileceği anlamına gelir.

Geçerli yapılandırma geçersiz kılınamazsa yöntemi döndürür nullve daha fazla yapılandırma gerçekleştirmeniz gerekiyorsa bu hesaba eklenmesi gerekir:

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

Unicode yapılandırması geçersiz kılınamazsa en fazla uzunluğun ayarlanacağına dikkat edin. Modelleri yalnızca her iki çağrı da başarılı olduğunda yapılandırmanız gerektiğinde ve CanSetIsUnicodeçağrısı CanSetMaxLength yaparak bunu önceden de kontrol edebilirsiniz:

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);
            }
        }
    }
}

Burada çağrısının HasMaxLength döndürülmediğinden nullemin olabilirsiniz. uygulamasından farklı propertyBuilderolabileceğinden yine de oluşturucu HasMaxLength örneğinin kullanılması önerilir.

Dekont

Diğer kurallar, bir kural değişiklik yaptıktan hemen sonra tetiklenmez, tüm kurallar geçerli değişikliği işlemeyi bitirene kadar geciktirilir.

IConventionContext

Tüm kural yöntemlerinin de bir IConventionContext<TMetadata> parametresi vardır. Bazı durumlarda yararlı olabilecek yöntemler sağlar.

Örnek: NotMappedAttribute kuralı

Bu kural, modele eklenen ve bu varlık türünü modelden kaldırmaya çalışan bir türü arar NotMappedAttribute . Ancak varlık türü modelden kaldırılırsa, uygulanan ProcessEntityTypeAdded diğer kuralların artık çalıştırılması gerekmez. Bu, çağrılarak StopProcessing()gerçekleştirilebilir:

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

Kurala geçirilen her oluşturucu nesnesi, modeli oluşturan nesnelere alt düzey erişim sağlayan bir Metadata özelliği kullanıma sunar. Özellikle, modeldeki belirli nesneler üzerinde yineleme yapmanıza ve bunlara Örnek: Tüm dize özellikleri için varsayılan uzunluk bölümünde görüldüğü gibi ortak yapılandırma uygulamanıza olanak sağlayan yöntemler vardır. Bu API, Toplu yapılandırmada gösterilene IMutableModel benzer.

Dikkat

Oluşturucular verilen yapılandırmanın Fluent API veya Veri Ek Açıklamaları kullanılarak önceden belirtilmiş bir şeyi geçersiz kılıp geçersiz kılmayacağını denetlediğinden, her zaman özellik olarak Builder kullanıma sunulan oluşturucuda yöntemleri çağırarak yapılandırma gerçekleştirmeniz tavsiye edilir.

Toplu yapılandırma için her yaklaşımın ne zaman kullanılacağı

Meta Veri API'lerini şu durumlarda kullanın:

  • Yapılandırmanın belirli bir zamanda uygulanması ve modeldeki sonraki değişikliklere tepki vermemesi gerekir.
  • Model oluşturma hızı çok önemlidir. Meta veri API'sinde daha az güvenlik denetimi vardır ve bu nedenle diğer yaklaşımlara göre biraz daha hızlı olabilir, ancak Derlenmiş modelin kullanılması daha da iyi başlangıç süreleri getirir.

Aşağıdaki durumlarda Kural öncesi model yapılandırmasını kullanın:

  • Uygulanabilirlik koşulu yalnızca türüne bağlı olduğundan basittir.
  • Yapılandırmanın herhangi bir noktada modele belirtilen türdeki bir özelliğin uygulanması gerekir ve Veri Ek Açıklamaları ve kurallarını geçersiz kılar

Aşağıdaki durumlarda Sonlandırma Kurallarını kullanın:

  • Uygulanabilirlik koşulu karmaşıktır.
  • Yapılandırma, Veri Ek Açıklamaları tarafından belirtilenleri geçersiz kılmamalıdır.

Aşağıdaki durumlarda Etkileşimli Kuralları kullanın:

  • Birden çok kural birbirine bağlıdır. Son haline getirme kuralları eklendikleri sırayla çalışır ve bu nedenle kuralları daha sonra sonlandırarak yapılan değişikliklere tepki veremez.
  • Mantık çeşitli bağlamlar arasında paylaşılır. Etkileşimli kurallar diğer yaklaşımlardan daha güvenlidir.