Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Ha egy szempontot ugyanúgy kell konfigurálni több entitástípus esetében, az alábbi technikák lehetővé teszik a kód duplikálásának csökkentését és a logika konszolidálását.
Tekintse meg az alább bemutatott kódrészleteket tartalmazó teljes mintaprojektet .
Tömeges konfiguráció az OnModelCreatingben
Minden visszaadott ModelBuilder objektum biztosít egy Model vagy Metadata tulajdonságot, amely alacsony szintű hozzáférést tesz lehetővé a modellt alkotó objektumokhoz. Vannak olyan módszerek, amelyek lehetővé teszik a modell bizonyos objektumainak iterálását, és általános konfigurációt alkalmazhat rájuk.
A következő példában a modell egy egyéni értéktípust Currencytartalmaz:
public readonly struct Currency
{
public Currency(decimal amount)
=> Amount = amount;
public decimal Amount { get; }
public override string ToString()
=> $"${Amount}";
}
Az ilyen típusú tulajdonságok alapértelmezés szerint nem találhatók meg, mivel az aktuális EF-szolgáltató nem tudja, hogyan képezheti le adatbázistípusra. Ez a kódrészlet OnModelCreating hozzáadja a típus Currency összes tulajdonságát, és egy értékkonvertert konfigurál egy támogatott típushoz : 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))
{
}
}
A Metadata API hátrányai
- A Fluent API-val ellentétben a modell minden módosítását explicit módon kell elvégezni. Ha például a
Currencytulajdonságok egy része konvenció szerint navigációként lett konfigurálva, akkor először el kell távolítania a CLR tulajdonságra hivatkozó navigációs parancsot, mielőtt entitástípus-tulajdonságot adna hozzá. #9117 javítani fogja ezt. - A konvenciók minden módosítás után futnak. Ha eltávolít egy konvenció által felderített navigációt, a konvenció újra lefut, és visszaállíthatja azt. Annak megakadályozására, hogy ez megtörténjen, késleltetnie kell az egyezmények végrehajtását addig, amíg a tulajdonság hozzáadása megtörténik a DelayConventions() hívásával és a visszaadott objektum későbbi eltávolításával, vagy a CLR tulajdonságot figyelmen kívül hagyásként kell megjelölnie a AddIgnored használatával.
- Előfordulhat, hogy az iteráció után entitástípusok lesznek hozzáadva, és a konfiguráció nem lesz alkalmazva rájuk. Ez általában megelőzhető, ha a kódot a végén
OnModelCreatinghelyezi el, de ha két egymástól függő konfigurációkészlettel rendelkezik, előfordulhat, hogy nem lesz olyan sorrend, amely lehetővé teszi az egységes alkalmazásukat.
Konvenció előtti konfiguráció
Az EF Core lehetővé teszi a leképezési konfiguráció egyszeri megadását egy adott CLR-típushoz; ezt a konfigurációt a rendszer a felderítéskor alkalmazza a modellben az adott típus összes tulajdonságára. Ezt "konvenciók előtti modellkonfigurációnak" nevezzük, mivel a modell elemeit a modellépítési konvenciók futtatása előtt konfigurálja. Az ilyen konfiguráció úgy kerül alkalmazásra, hogy felülbíráljuk ConfigureConventions a forrásból származtatott DbContext típust.
Ez a példa bemutatja, hogyan konfigurálhatja a típus Currency összes tulajdonságát értékkonverterrel:
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder
.Properties<Currency>()
.HaveConversion<CurrencyConverter>();
}
Ez a példa bemutatja, hogyan konfigurálhat bizonyos aspektusokat az összes típustulajdonságon string:
configurationBuilder
.Properties<string>()
.AreUnicode(false)
.HaveMaxLength(1024);
Megjegyzés:
A hívásban ConfigureConventions megadott típus lehet alaptípus, interfész vagy általános típusdefiníció. Az összes egyező konfiguráció a legkevésbé meghatározott sorrendben lesz alkalmazva:
- Interfész
- Alaptípus
- Általános típusdefiníció
- Nem null értékű értéktípus
- Pontos típus
Fontos
A konvenció előtti konfiguráció egyenértékű az explicit konfigurációval, amely akkor lesz alkalmazva, amikor egyező objektumot ad hozzá a modellhez. Felülbírálja az összes konvenciót és adatjegyzetet. A fenti konfigurációval például az összes sztring idegenkulcs-tulajdonság nem unicode-ként jön létre, 1024-es hosszúsággal MaxLength, még akkor is, ha ez nem egyezik az alapkulccsal.
Típusok figyelmen kívül hagyása
A konvenció előtti konfiguráció lehetővé teszi egy típus figyelmen kívül hagyását, és megakadályozhatja, hogy a konvenciók entitástípusként vagy entitástípus tulajdonságaként fedezzék fel:
configurationBuilder
.IgnoreAny(typeof(IList<>));
Alapértelmezett típusleképezés
Az EF általában képes olyan típusú állandókkal rendelkező lekérdezéseket lefordítani, amelyeket a szolgáltató nem támogat, feltéve, hogy megadott egy értékkonvertert egy ilyen típusú tulajdonsághoz. Az ilyen típusú tulajdonságokat nem tartalmazó lekérdezésekben azonban az EF nem tudja megtalálni a megfelelő értékkonvertert. Ebben az esetben lehetőség van felhívni DefaultTypeMapping egy szolgáltató típusú megfeleltetés hozzáadására vagy felülbírálására.
configurationBuilder
.DefaultTypeMapping<Currency>()
.HasConversion<CurrencyConverter>();
A konvenció előtti konfiguráció korlátozásai
- Ezzel a megközelítéssel számos szempont nem konfigurálható. #6787 kiterjeszti ezt több típusra.
- A konfigurációt jelenleg csak a CLR-típus határozza meg. A #20418 egyéni predikátumokat engedélyezne.
- Ezt a konfigurációt a rendszer a modell létrehozása előtt hajtja végre. Ha az alkalmazás során ütközések lépnek fel, a kivételverem-nyomkövetés nem fogja tartalmazni a
ConfigureConventionsmetódust, így nehezebb lehet megtalálni az okot.
Egyezmények
Az EF Core-modellépítési konvenciók olyan osztályokat tartalmaznak, amelyek olyan logikát tartalmaznak, amely a modell létrehozásakor végrehajtott módosítások alapján aktiválódik. Ez megőrzi a modell up-todátumát, amikor explicit módon konfigurálnak, leképezési attribútumokat alkalmaznak, és más konvenciók futnak. A részvételhez minden konvenció egy vagy több interfészt implementál, amelyek meghatározzák, hogy mikor aktiválódik a megfelelő módszer. Egy implementálási IEntityTypeAddedConvention konvenció például akkor aktiválódik, amikor új entitástípust ad hozzá a modellhez. Hasonlóképpen, egy konvenció, amely mind a IForeignKeyAddedConvention, mind a IKeyAddedConvention megvalósítja, akkor aktiválódik, amikor hozzáadnak egy kulcsot vagy idegen kulcsot a modellhez.
A modellépítési konvenciók hatékony módszert jelentenek a modellkonfiguráció szabályozására, de összetettek és nehezen kezelhetők. A konvenció előtti modellkonfiguráció sok esetben használható a tulajdonságok és típusok közös konfigurációjának egyszerű megadására.
Új konvenció hozzáadása
Példa: A megkülönböztető tulajdonságok hosszának korlátozása
A hierarchiánkénti táblaöröklés-leképezési stratégiához diszkriminatív oszlopra van szükség, amely meghatározza, hogy melyik típus jelenik meg egy adott sorban. Alapértelmezés szerint az EF egy korlátlan karakterlánc oszlopot használ a diszkriminátorhoz, amely biztosítja, hogy bármilyen diszkriminátor hosszúság esetén működni fog. A diszkriminatív sztringek maximális hosszának korlátozása azonban hatékonyabbá teheti a tárolást és a lekérdezéseket. Hozzunk létre egy új konvenciót, amely ezt fogja tenni.
Az EF Core-modellkészítési konvenciók a modell létrehozásakor végrehajtott módosítások alapján aktiválódnak. Ez megőrzi a modell up-todátumát, amikor explicit módon konfigurálnak, leképezési attribútumokat alkalmaznak, és más konvenciók futnak. A részvételhez minden konvenció egy vagy több interfészt implementál, amelyek meghatározzák, hogy mikor aktiválódik az egyezmény. Egy implementálási IEntityTypeAddedConvention konvenció például akkor aktiválódik, amikor új entitástípust ad hozzá a modellhez. Hasonlóképpen, egy konvenció, amely mind a IForeignKeyAddedConvention, mind a IKeyAddedConvention megvalósítja, akkor aktiválódik, amikor hozzáadnak egy kulcsot vagy idegen kulcsot a modellhez.
A implementálandó felületek ismerete nehézkes lehet, mivel a modell egy ponton történő konfigurációja egy későbbi időpontban módosítható vagy eltávolítható. Előfordulhat például, hogy egy kulcs konvencióval jön létre, de később lecserélődik, ha egy másik kulcs explicit módon van konfigurálva.
Tegyük ezt egy kicsit konkrétabbá a diszkriminatív hosszúságú egyezmény végrehajtására tett első kísérlettel:
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);
}
}
}
Ez a konvenció megvalósítja a IEntityTypeBaseTypeChangedConvention-t, ami azt jelenti, hogy aktiválódik, amikor csak egy entitástípus megfeleltetett öröklési hierarchiája módosul. A konvenció ezután megkeresi és konfigurálja a hierarchiához tartozó karakterlánc diszkriminátor jellemzőt.
Ezt a konvenciót úgy alkalmazzák, hogy meghívják a Add a ConfigureConventions-ben.
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder.Conventions.Add(_ => new DiscriminatorLengthConvention1());
}
Megjegyzés:
Ahelyett, hogy közvetlenül hozzáadná a konvenció egy példányát, a Add metódus elfogad egy gyárat a konvenció példányainak létrehozásához. Ez lehetővé teszi, hogy a konvenció az EF Core belső szolgáltatótól származó függőségeket használjon. Mivel ez a konvenció nem rendelkezik függőségekkel, a szolgáltató paraméter neve _azt jelzi, hogy soha nem használják.
A modell létrehozása és az Post entitástípus megvizsgálása azt mutatja, hogy ez működött – a diszkriminatív tulajdonság most már 24-es maximális hosszra van konfigurálva:
Discriminator (no field, string) Shadow Required AfterSave:Throw MaxLength(24)
De mi történik, ha most explicit módon konfigurálunk egy másik megkülönböztető tulajdonságot? Például:
modelBuilder.Entity<Post>()
.HasDiscriminator<string>("PostTypeDiscriminator")
.HasValue<Post>("Post")
.HasValue<FeaturedPost>("Featured");
A modell hibakeresési nézetét tekintve azt látjuk, hogy a diszkriminatív hossz már nincs konfigurálva.
PostTypeDiscriminator (no field, string) Shadow Required AfterSave:Throw
Ennek az az oka, hogy a konvencióban konfigurált diszkriminatív tulajdonságot később eltávolítottuk az egyéni diszkriminatív hozzáadásakor. Ezt megpróbálhatjuk kijavítani úgy, hogy egy másik felületet vezetünk be az egyezményünkben, hogy reagáljunk a diszkriminatív változásokra, de nem könnyű kitalálni, hogy melyik felületet kell implementálni.
Szerencsére van egy egyszerűbb megközelítés. Sok esetben nem számít, hogy a modell hogyan néz ki a felépítése során, amíg a végső modell helyes. Emellett a gyakran alkalmazni kívánt konfigurációnak nem kell más konvenciók aktiválása a reagáláshoz. Ezért a konvenciónk képes implementálni IModelFinalizingConvention.
A modell véglegesítési konvenciói az összes többi modell létrehozása után futnak, és így hozzáférhetnek a modell majdnem végleges állapotához. Ez szemben áll azokkal az interaktív konvenciókkal , amelyek reagálnak az egyes modellmódosításokra, és gondoskodnak arról, hogy a modell up-to-date legyen a OnModelCreating metódus végrehajtásának bármely pontján. A modellvéglegesítési konvenció általában az egész modellen végigmegy, miközben konfigurálja a modell elemeit. Ebben az esetben tehát minden diszkriminatívt megtalálunk a modellben, és konfiguráljuk:
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);
}
}
}
}
Miután ezzel az új konvencióval létrehozta a modellt, azt tapasztaljuk, hogy a diszkriminatív hossz helyesen van konfigurálva, annak ellenére, hogy testre lett szabva:
PostTypeDiscriminator (no field, string) Shadow Required AfterSave:Throw MaxLength(24)
Egy lépésnyire haladhatunk tovább, és a maximális hosszt a leghosszabb diszkriminatív érték hosszára konfigurálhatjuk:
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);
}
}
}
}
A diszkriminatív oszlop maximális hossza 8, ami a használatban lévő leghosszabb diszkriminatív érték, a "Kiemelt" hossza.
PostTypeDiscriminator (no field, string) Shadow Required AfterSave:Throw MaxLength(8)
Példa: Az összes sztringtulajdonság alapértelmezett hossza
Tekintsünk meg egy másik példát, ahol egy véglegesítési konvenció használható – a karakterlánc-tulajdonságok alapértelmezett maximális hosszának beállításával. A konvenció az előző példához hasonlóan néz ki:
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);
}
}
}
Ez a konvenció elég egyszerű. Megkeresi a modell összes sztringtulajdonságát, és a maximális hosszát 512-re állítja. A hibakeresési nézetben a Post tulajdonságaira tekintve azt látjuk, hogy az összes szöveges tulajdonság maximális hossza most 512 karakter.
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)
Megjegyzés:
Ugyanez a konvenció előtti konfigurációval is megvalósítható, de egy konvenció használatával tovább szűrheti az alkalmazható tulajdonságokat, és az adatjegyzetek esetében felülbírálhatja a konfigurációt.
Végül, mielőtt elhagyjuk ezt a példát, mi történik, ha egyszerre használjuk a MaxStringLengthConvention és DiscriminatorLengthConvention3 elemeket? A válasz az, hogy attól függ, hogy milyen sorrendben vannak hozzáadva, mivel a modell véglegesítési konvenciók a hozzáadásuk sorrendjében futnak. Tehát ha MaxStringLengthConvention utoljára hozzáadjuk, akkor az utolsóként fog futni, és a diszkriminatív tulajdonság maximális hosszát 512-re állítja be. Ezért ebben az esetben jobb, ha a DiscriminatorLengthConvention3 elemet utoljára adja hozzá, hogy csak a diszkriminatív tulajdonságok esetében felülírhassa az alapértelmezett maximális hosszt, miközben az összes többi szöveges tulajdonságot 512-ként hagyja.
Meglévő konvenció cseréje
Néha ahelyett, hogy teljesen eltávolítanánk egy meglévő konvenciót, inkább egy olyan konvencióra szeretnénk cserélni, amely alapvetően ugyanazt a dolgot teszi, de megváltozott viselkedéssel. Ez azért hasznos, mert a meglévő konvenció már implementálja a megfelelő módon aktiválandó interfészeket.
Példa: Opt-in tulajdonságleképezés
Az EF Core konvenciók szerint leképezi az összes nyilvános olvasási-írási tulajdonságot. Előfordulhat, hogy ez nem felel meg az entitástípusok definiálásának. Ennek módosításához lecserélhetjük a PropertyDiscoveryConvention saját implementációnkra, amely nem képez le semmilyen tulajdonságot, hacsak nem explicit módon van leképezve OnModelCreating-ben vagy egy új attribútummal Persist megjelölve.
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public sealed class PersistAttribute : Attribute
{
}
Íme az új konvenció:
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;
}
}
}
}
Jótanács
Beépített konvenció cseréjekor az új konvenció implementációnak a meglévő konvencióosztálytól kell örökölnie. Vegye figyelembe, hogy egyes konvenciók relációs vagy szolgáltatóspecifikus implementációkkal rendelkeznek, ebben az esetben az új konvenció implementációnak a használt adatbázis-szolgáltató legspecifikusabb konvenciós osztályától kell örökölnie.
A konvenció ezután a Replace módszer használatával van regisztrálva ConfigureConventions.
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder.Conventions.Replace<PropertyDiscoveryConvention>(
serviceProvider => new AttributeBasedPropertyDiscoveryConvention(
serviceProvider.GetRequiredService<ProviderConventionSetBuilderDependencies>()));
}
Jótanács
Ez az az eset, amikor a meglévő konvenció függőségekkel rendelkezik, amelyeket a függőségi ProviderConventionSetBuilderDependencies objektum jelöl. Ezek az intern szolgáltató segítségével GetRequiredService kerülnek beszerzésre, majd átadásra a konvenciókonstruktor számára.
Figyelje meg, hogy ez a konvenció lehetővé teszi a mezők leképezését (a tulajdonságokon kívül) mindaddig, amíg meg vannak jelölve.[Persist] Ez azt jelenti, hogy titkos mezőket használhatunk rejtett kulcsként a modellben.
Vegyük például az alábbi entitástípusokat:
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; }
}
Az alábbi entitástípusokból készült modell a következő:
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
Normál esetben a IsClean le lett volna képezve, de mivel nincs megjelölve [Persist], most nem leképzett tulajdonságként van kezelve.
Jótanács
Ez a konvenció nem implementálható modell-véglegesítési konvencióként, mert léteznek olyan modell-véglegesítési konvenciók, amelyeket a tulajdonság leképezése után kell futtatni a további konfiguráláshoz.
Konvenciók végrehajtási szempontjai
Az EF Core nyomon követi, hogyan készült minden konfiguráció. Ezt az enumerálás jelöli ConfigurationSource . A konfiguráció különböző típusai a következők:
-
Explicit: A modellelem explicit módon lett konfigurálva a következőben:OnModelCreating -
DataAnnotation: A modellelem a CLR-típuson egy leképezési attribútum (más néven adatjegyzet) használatával lett konfigurálva -
Convention: A modellelemet egy modellépítési konvenció konfigurálta
A konvenciók soha nem bírálhatják felül a DataAnnotation vagy Explicit jelzésű konfigurációt. Ez egy konvenciókészítővel érhető el, például a IConventionPropertyBuilder tulajdonságból beszerzett Builder segítségével. Például:
property.Builder.HasMaxLength(512);
A konvenciós szerkesztő meghívása HasMaxLength csak akkor állítja be a maximális hosszt, ha azt még nem konfigurálta egy leképezési attribútum vagy OnModelCreating segítségével.
Az ilyen szerkesztő metódusoknak is van egy második paramétere: fromDataAnnotation. Ezt akkor állítsa be, true ha a konvenció egy leképezési attribútum nevében állítja be a konfigurációt. Például:
property.Builder.HasMaxLength(512, fromDataAnnotation: true);
Ez a beállítás a következőre ConfigurationSourceállítja az DataAnnotation értéket, ami azt jelenti, hogy az érték mostantól felülírható explicit leképezésselOnModelCreating, de nem leképezési attribútumkonvenciával.
Ha az aktuális konfigurációt nem lehet felülírni, akkor a metódus visszatér null, ezt figyelembe kell venni, ha további konfigurációt kell végrehajtania:
property.Builder.HasMaxLength(512)?.IsUnicode(false);
Figyelje meg, hogy ha a Unicode-konfiguráció nem bírálható felül, a maximális hossz továbbra is be lesz állítva. Ha csak akkor kell konfigurálnia az aspektusokat, ha mindkét hívás sikeres, akkor ezt előre ellenőrizheti a következő hívással 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);
}
}
}
}
Itt biztosak lehetünk abban, hogy a HasMaxLength hívás nem fog visszatérni null. Továbbra is ajánlott a visszaadott HasMaxLength szerkesztőpéldány használata, mivel az eltérhet a következőtől propertyBuilder: .
Megjegyzés:
A többi konvenció nem aktiválódik azonnal, miután egy konvenció módosítást végez, és mindaddig késlelteti őket, amíg az összes konvenció befejezi az aktuális módosítás feldolgozását.
IConventionContext
Minden konvenciós metódusnak van paramétere IConventionContext<TMetadata> is. Olyan módszereket biztosít, amelyek bizonyos esetekben hasznosak lehetnek.
Példa: NotMappedAttribute konvenció
Ez a konvenció egy olyan típust keres NotMappedAttribute , amely hozzá van adva a modellhez, és megpróbálja eltávolítani az entitástípust a modellből. Ha azonban az entitástípus el van távolítva a modellből, akkor a többi implementálási ProcessEntityTypeAdded konvenciónak már nem kell futnia. Ez a következő hívással StopProcessing()érhető el:
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
A konvenciónak átadott összes szerkesztőobjektum olyan tulajdonságot Metadata tesz elérhetővé, amely alacsony szintű hozzáférést biztosít a modellt alkotó objektumokhoz. A módszerek különösen lehetővé teszik, hogy iteráljunk a modell egyes objektumain, és közös konfigurációt alkalmazzunk rájuk, ahogy az a Példa: Az összes karakterlánc-tulajdonság alapértelmezett hossza részben látható. Ez az API hasonló a IMutableModel láthatóhoz.
Figyelmeztetés
Javasoljuk, hogy mindig végezze el a konfigurációt a tulajdonságként Builder közzétett szerkesztő metódusainak meghívásával, mert a szerkesztők ellenőrzik, hogy az adott konfiguráció felülírja-e a Fluent API-val vagy adatjegyzetekkel már megadott konfigurációt.
Mikor érdemes használni az egyes módszereket a tömeges konfigurációhoz?
A Metadata API használata a következő esetekben:
- A konfigurációt egy bizonyos időpontban kell alkalmazni, és nem kell reagálni a modell későbbi változásaira.
- A modellépítés sebessége nagyon fontos. A Metadata API-nak kevesebb biztonsági ellenőrzése van, így valamivel gyorsabb lehet, mint más megközelítések, azonban a lefordított modell használata még jobb indítási időket eredményezne.
Konvenció előtti modellkonfigurációt akkor használjon, ha:
- Az alkalmazhatósági feltétel egyszerű, mivel csak a típustól függ.
- A konfigurációt minden olyan ponton alkalmazni kell, amikor a modell egy adott típusú tulajdonságot ad hozzá, és felülbírálja az adatjegyzeteket és konvenciókat
Véglegesítési konvenciók használata a következő esetekben:
- Az alkalmazhatósági feltétel összetett.
- A konfigurációnak nem szabad felülbírálnia az adatjegyzetek által megadottakat.
Interaktív konvenciók használata a következő esetekben:
- Több konvenció egymástól függ. A véglegesítési konvenciók a hozzáadásuk sorrendjében futnak, ezért nem tudnak reagálni a későbbi véglegesítési konvenciók által végrehajtott módosításokra.
- A logika több környezet között is meg van osztva. Az interaktív konvenciók biztonságosabbak, mint más megközelítések.