Az EF Core 3.x kompatibilitástörő változásai
Az alábbi API- és viselkedésváltozások a meglévő alkalmazások 3.x-es verzióra való frissítésekor megszakíthatják a meglévő alkalmazásokat. Azok a változások, amelyek várhatóan csak az adatbázis-szolgáltatókat érintik, a szolgáltatói változásokalatt vannak dokumentálva.
Összefoglalás
Nagy hatású változások
A LINQ-lekérdezések kiértékelése már nem történik meg az ügyfélen
nyomon követési probléma #14935Lásd az 12795-ös
Régi viselkedés
A 3.0 előtt, amikor az EF Core nem tudott egy lekérdezés részét képező kifejezést SQL-vé vagy paraméterzé konvertálni, automatikusan kiértékelte a kifejezést az ügyfélen. Alapértelmezés szerint a potenciálisan költséges kifejezések ügyfélértékelése csak figyelmeztetést váltott ki.
Új viselkedés
A 3.0-tól kezdődően az EF Core csak a legfelső szintű előrejelzésben (a lekérdezés utolsó Select()
hívásában) lévő kifejezések kiértékelését engedélyezi az ügyfélen.
Ha a lekérdezés bármely más részén lévő kifejezések nem konvertálhatók SQL-vé vagy paraméterré, kivételt okoz.
Miért
A lekérdezések automatikus ügyfél-kiértékelése számos lekérdezés végrehajtását teszi lehetővé, még akkor is, ha a lekérdezések fontos részei nem fordíthatók le.
Ez a viselkedés váratlan és potenciálisan káros következményekhez vezethet, amelyek csak az élesítési környezetben válnak nyilvánvalóvá.
Ha például egy Where()
hívás nem fordítható le, az okozhatja, hogy a tábla összes sora át lesz helyezve az adatbázis-kiszolgálóról, és a szűrőt az ügyfélre kell alkalmazni.
Ez a helyzet könnyen észrevétlen maradhat, ha a tábla csak néhány sort tartalmaz a fejlesztés során, de nagy problémát okoz, amikor az alkalmazás éles környezetbe kerül, ahol a tábla több millió sort is tartalmazhat.
Az ügyfélértékelési figyelmeztetések túl könnyen figyelmen kívül hagyhatónak bizonyultak a fejlesztés során.
Emellett az ügyfél automatikus kiértékelése olyan problémákhoz vezethet, amelyekben az egyes kifejezések lekérdezésfordításának javítása nem szándékos kompatibilitástörő változásokat okozott a kiadások között.
Enyhítő intézkedések
Ha egy lekérdezés nem fordítható le teljesen, akkor vagy írja át a lekérdezést lefordítható formában, vagy használja AsEnumerableAsync()
, ToListAsync()
vagy hasonló módon, hogy explicit módon visszahozza az adatokat az ügyfélhez, ahol aztán tovább feldolgozható LINQ-to-Objects használatával.
Közepes hatású változások
Az Entity Framework Core már nem része a ASP.NET Core megosztott keretrendszerének
nyomon követési problémák bejelentései#325
Régi viselkedés
ASP.NET Core 3.0 előtt, amikor hozzáadtál egy csomaghivatkozást Microsoft.AspNetCore.App
-hoz vagy Microsoft.AspNetCore.All
-hez, az EF Core-t, valamint néhány EF Core-adatszolgáltatót, például az SQL Server-szolgáltatót is tartalmazná.
Új viselkedés
A 3.0-tól kezdődően a ASP.NET Core megosztott keretrendszere nem tartalmaz EF Core-t vagy EF Core-adatszolgáltatókat.
Miért
A módosítás előtt az EF Core beszerzése különböző lépéseket igényelt attól függően, hogy az alkalmazás ASP.NET Core-ra és SQL Serverre vagy más környezetre lett-e célozva. A ASP.NET Core frissítése az EF Core és az SQL Server szolgáltató frissítését is kényszerítette, ami nem mindig kívánatos.
Ezzel a változással az EF Core megszerzése minden szolgáltatónál, a támogatott .NET-implementációkban és az alkalmazástípusoknál is egységes. A fejlesztők mostantól pontosan szabályozhatják az EF Core és az EF Core adatszolgáltatók frissítését is.
Csökkentések
Ha az EF Core-t ASP.NET Core 3.0-alkalmazásokban vagy bármely más támogatott alkalmazásban szeretné használni, explicit módon adjon hozzá csomaghivatkozást az alkalmazás által használt EF Core-adatbázis-szolgáltatóhoz.
Az EF Core parancssori eszköze, a dotnet ef, már nem része a .NET Core SDK-nak
Régi viselkedés
A 3.0 előtt a dotnet ef
eszköz a .NET Core SDK része volt, és minden projekt parancssorából használható volt további lépések nélkül.
Új viselkedés
A 3.0-tól kezdődően a .NET SDK nem tartalmazza a dotnet ef
eszközt, ezért használat előtt explicit módon telepítenie kell helyi vagy globális eszközként.
Miért
Ez a módosítás lehetővé teszi a dotnet ef
rendszeres .NET CLI-eszközként való terjesztését és frissítését a NuGeten, összhangban azzal a ténnyel, hogy az EF Core 3.0 is mindig NuGet-csomagként van elosztva.
Enyhítő intézkedések
A migrációk vagy egy DbContext
sablon kezeléséhez telepítse a dotnet-ef
-et globális eszközként.
dotnet tool install --global dotnet-ef
Helyi eszközt is beszerezhet, ha egy olyan projekt függőségeit állítja vissza, amely eszközfüggőségként deklarálja azt egy eszközjegyzékfájlhasználatával.
Kis hatású módosítások
A FromSql, az ExecuteSql és az ExecuteSqlAsync átnevezve lett
Fontos
ExecuteSqlCommand
és ExecuteSqlCommandAsync
elavultak. Használja inkább ezeket a metódusokat.
Régi viselkedés
Az EF Core 3.0 előtt ezek a metódusnevek túlterheltek voltak, hogy normál sztringgel vagy egy SQL-be és paraméterekbe interpolálandó sztringgel is működjenek.
Új viselkedés
Az EF Core 3.0-tól kezdve FromSqlRaw
, ExecuteSqlRaw
és ExecuteSqlRawAsync
használatával hozzon létre egy paraméteres lekérdezést, amelyben a paramétereket a lekérdezési sztringtől elkülönítve adja át.
Például:
context.Products.FromSqlRaw(
"SELECT * FROM Products WHERE Name = {0}",
product.Name);
A FromSqlInterpolated
, ExecuteSqlInterpolated
és ExecuteSqlInterpolatedAsync
használatával olyan paraméteres lekérdezést hozhat létre, amelyben a paraméterek egy interpolált lekérdezési sztring részeként lesznek átadva.
Például:
context.Products.FromSqlInterpolated(
$"SELECT * FROM Products WHERE Name = {product.Name}");
Vegye figyelembe, hogy mindkét fenti lekérdezés ugyanazt a paraméteres SQL-t fogja előállítani ugyanazokkal az SQL-paraméterekkel.
Miért
Az ilyen metódusok túlterhelése miatt nagyon könnyű véletlenül meghívni a nyers sztringmetódust, amikor a szándék az interpolált sztringmetódus meghívása volt, és fordítva. Ez azt eredményezheti, hogy a lekérdezések nem lesznek paraméterezve, amikor kellett volna.
Enyhítések
Váltson az új metódusnevek használatára.
A tárolt eljárással használt FromSql-metódus nem írható össze
nyomon követési probléma #15392
Régi viselkedés
Az EF Core 3.0 előtt a FromSql metódus megpróbálta észlelni, hogy az átadott SQL-t meg lehet-e alkotni. Ügyfélértékelést végzett, amikor az SQL nem volt összeállítható, mint egy tárolt eljárás. Az alábbi lekérdezés a kiszolgálón tárolt eljárás futtatásával és a FirstOrDefault ügyféloldalon történő végrehajtásával működött.
context.Products.FromSqlRaw("[dbo].[Ten Most Expensive Products]").FirstOrDefault();
Új viselkedés
Az EF Core 3.0-tól kezdve az EF Core nem próbálja elemezni az SQL-t. Tehát ha a FromSqlRaw/FromSqlInterpolated után állít össze, akkor az EF Core al-lekérdezéssel fogja összeállítani az SQL-t. Ha tehát egy tárolt eljárást használ összetétellel, akkor kivételt fog kapni az érvénytelen SQL-szintaxis alól.
Miért
Az EF Core 3.0 nem támogatja az automatikus ügyfélértékelést, mivel hajlamos hibákra, ahogy azt ittkifejtették.
Enyhítések
Ha a FromSqlRaw/FromSqlInterpolated fájlban tárolt eljárást használ, tudja, hogy az nem írható össze, így közvetlenül a FromSql metódushívás után hozzáadhat AsEnumerable
/AsAsyncEnumerable
, hogy elkerülje a kiszolgálóoldali összetételt.
context.Products.FromSqlRaw("[dbo].[Ten Most Expensive Products]").AsEnumerable().FirstOrDefault();
A FromSql-metódusok csak lekérdezésgyökereken adhatók meg
nyomon követési probléma #15704
Régi viselkedés
Az EF Core 3.0 előtt a FromSql
metódus bárhol megadható a lekérdezésben.
Új viselkedés
Az EF Core 3.0-tól kezdve az új FromSqlRaw
és FromSqlInterpolated
metódusok (amelyek felváltják a FromSql
) csak lekérdezésgyökereken, azaz közvetlenül a DbSet<>
adhatók meg. Ha máshol próbálja meg megadni őket, fordítási hiba fog következni.
Miért
A FromSql
megadása bárhol máshol, mint egy DbSet
-en, nem jár hozzáadott jelentéssel vagy értékkel, és bizonyos helyzetekben kétértelműséget okozhat.
Enyhítések
A FromSql
meghívásokat úgy kell áthelyezni, hogy közvetlenül azon a DbSet
-en legyenek, amelyre vonatkoznak.
A nem követési lekérdezések már nem hajtanak végre identitásfeloldási műveleteket
nyomon követési probléma #13518
Régi viselkedés
Az EF Core 3.0 előtt ugyanaz az entitáspéldány lesz használva egy adott típusú és azonosítójú entitás minden előfordulásához. Ez megegyezik a lekérdezések nyomon követésének viselkedésével. Ez a lekérdezés például a következő:
var results = await context.Products.Include(e => e.Category).AsNoTracking().ToListAsync();
Minden Product
esetében, amely az adott kategóriához van társítva, ugyanazt a Category
példányt adná vissza.
Új viselkedés
Az EF Core 3.0-tól kezdve különböző entitáspéldányok jönnek létre, amikor egy adott típusú és azonosítójú entitás a visszaadott gráf különböző helyeinél jelenik meg. A lekérdezés például most minden Product
esetén egy új Category
-példányt ad vissza, még akkor is, ha két termék ugyanahhoz a kategóriához van társítva.
Miért
Az identitásfeloldás (vagyis annak meghatározása, hogy egy entitás típusa és azonosítója megegyezik a korábban észlelt entitással) további teljesítmény- és memóriaterhelést jelent. Ez általában ellentmond annak az eredeti célnak, amiért a nyomkövetés nélküli lekérdezéseket használják. Bár az identitásfeloldás néha hasznos lehet, nem szükséges, ha az entitásokat szerializálni kell, és egy ügyfélnek kell elküldeni, ami gyakori a nyomkövetés nélküli lekérdezések esetében.
Enyhítések
Használjon nyomkövetési lekérdezést, ha identitásfeloldás szükséges.
Az ideiglenes kulcsértékek már nincsenek entitáspéldányokra beállítva
Nyomon követési probléma #12378
Régi viselkedés
Az EF Core 3.0 előtt az ideiglenes értékek az összes olyan kulcstulajdonsághoz lettek hozzárendelve, amelyek később valós értéket hoztak létre az adatbázis által. Ezek az ideiglenes értékek általában nagy negatív számok voltak.
Új viselkedés
A 3.0-tól kezdődően az EF Core az entitás nyomkövetési információinak részeként tárolja az ideiglenes kulcsértéket, és magát a kulcstulajdonságot változatlanul hagyja.
Miért
Ez a módosítás megakadályozta, hogy az ideiglenes kulcsértékek hibásan állandósuljanak, amikor egy, bizonyos DbContext
-példány által korábban nyomon követett entitást áthelyeznek egy másik DbContext
-példányba.
Enyhítések
Azok az alkalmazások, amelyek elsődleges kulcsértékeket rendelnek idegen kulcsokhoz az entitások közötti társítások létrehozásához, a régi viselkedéstől függhetnek, ha az elsődleges kulcsok tárolóalapúak, és az Added
állapotban lévő entitásokhoz tartoznak.
Ezt a következő lépéssel lehet elkerülni:
- Nem használ tároló által generált kulcsokat.
- A navigációs tulajdonságok beállítása a kapcsolatok kialakításához, ahelyett, hogy az idegen kulcsértékeket állítaná be.
- Szerezze be a tényleges ideiglenes kulcsértékeket az entitás nyomkövetési adataiból.
A
context.Entry(blog).Property(e => e.Id).CurrentValue
például az ideiglenes értéket adja vissza annak ellenére, hogyblog.Id
még nincs beállítva.
DetectChanges az áruház által létrehozott kulcsértékeket tiszteli
nyomon követési probléma #14616
Régi viselkedés
Az EF Core 3.0 előtt a DetectChanges
által talált nem nyomon követett entitások Added
állapotban lesznek nyomon követve, és SaveChanges
meghívásakor új sorként lesznek beszúrva.
Új viselkedés
Az EF Core 3.0-tól kezdődően, ha egy entitás generált kulcsértékeket használ, és beállít néhány kulcsértéket, akkor az entitás Modified
állapotban lesz nyomon követve.
Ez azt jelenti, hogy a rendszer feltételezi, hogy az entitás egy sora létezik, és SaveChanges
hívásakor frissül.
Ha a kulcs értéke nincs beállítva, vagy ha az entitás típusa nem generált kulcsokat használ, akkor az új entitás továbbra is Added
lesz nyomon követve, mint az előző verziókban.
Miért
Ez a módosítás egyszerűbbé és konzisztensebbé tette a leválasztott entitásdiagramok használatát az áruház által létrehozott kulcsok használata közben.
Enyhítése
Ez a módosítás megszakíthatja az alkalmazásokat, ha egy entitástípus generált kulcsok használatára van konfigurálva, de a kulcsértékek explicit módon vannak beállítva az új példányokhoz. A javítás célja, hogy explicit módon konfigurálja a kulcstulajdonságokat úgy, hogy ne használjanak generált értékeket. Például a fluent API-val:
modelBuilder
.Entity<Blog>()
.Property(e => e.Id)
.ValueGeneratedNever();
Vagy adatjegyzetekkel:
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string Id { get; set; }
A kaszkádolt törlések alapértelmezés szerint azonnal történnek
nyomon követési probléma #10114
Régi viselkedés
A 3.0-s verzió előtt az EF Core kaszkádolt műveleteket alkalmazott (a függő entitások törlése a szükséges tag törlésekor vagy a szükséges taggal való kapcsolat megszakadásakor) mindaddig nem történt meg, amíg a SaveChanges meghívása meg nem történt.
Új viselkedés
A 3.0-tól kezdődően az EF Core kaszkádolt műveleteket alkalmaz, amint az eseményindító feltétel észlelhető.
Ha például meghívja context.Remove()
egy fő entitás törlésére, az azzal jár, hogy az összes nyomon követett kapcsolódó kötelező függőség azonnal Deleted
beállításra kerül.
Miért
Ez a módosítás az adatkötési és naplózási forgatókönyvek felhasználói élményének javítása érdekében történt, ahol fontos tisztában lenni azzal, hogy mely entitások törlődnek SaveChanges
meghívása előtt.
Mérséklések
Az előző viselkedés a context.ChangeTracker
beállításaival állítható vissza.
Például:
context.ChangeTracker.CascadeDeleteTiming = CascadeTiming.OnSaveChanges;
context.ChangeTracker.DeleteOrphansTiming = CascadeTiming.OnSaveChanges;
A kapcsolódó entitások türelmetlen betöltése most egyetlen lekérdezésben történik
18022- nyomon követésével kapcsolatos probléma
Régi viselkedés
A 3.0 előtt a kollekció navigációk Include
operátorokkal való betöltése több lekérdezést is generált a relációs adatbázisban, egyet minden kapcsolódó entitástípushoz.
Új viselkedés
A 3.0-tól kezdve az EF Core egyetlen lekérdezést hoz létre JOIN-ekkel a relációs adatbázisokon.
Miért
Az egyetlen LINQ-lekérdezés implementálásához több lekérdezés kiadása számos problémát okozott, beleértve a negatív teljesítményt, mivel több adatbázis-kerekítésre volt szükség, valamint adategyenlőségi problémákat, mivel az egyes lekérdezések az adatbázis különböző állapotát figyelhették meg.
Enyhítő intézkedések
Bár ez technikailag nem jelent kompatibilitástörő változást, jelentős hatással lehet az alkalmazás teljesítményére, ha egyetlen lekérdezés nagy számú Include
operátort tartalmaz a gyűjteménynavigációkban.
További információkért és a lekérdezések hatékonyabb újraírásához tekintse meg ezt a megjegyzést.
**
A DeleteBehavior.Restrict tisztább szemantikával rendelkezik
Nyomon követési probléma #12661
Régi viselkedés
3.0 előtt a DeleteBehavior.Restrict
külső kulcsokat hozott létre az adatbázisban Restrict
szemantikával, de a belső összehangolást is nem nyilvánvaló módon megváltoztatta.
Új viselkedés
A 3.0-val kezdődően a DeleteBehavior.Restrict
biztosítja, hogy a külső kulcsok Restrict
szemantikával legyenek létrehozva , vagyis kaszkádok nélkül; korlátozásmegsértés esetén – anélkül, hogy ez hatással lenne az EF belső javítására.
Miért
Ez a módosítás azért történt, hogy a tapasztalat javítása érdekében a DeleteBehavior
-t intuitív módon, váratlan mellékhatások nélkül lehessen használni.
Enyhítések
Az előző viselkedés a DeleteBehavior.ClientNoAction
használatával állítható vissza.
A lekérdezéstípusok entitástípusokkal vannak összesítve
Nyomon követési probléma #14194
Régi viselkedés
Az EF Core 3.0 előtt lekérdezéstípusok olyan adatok lekérdezésére voltak használhatóak, amelyek nem strukturált módon határoznak meg elsődleges kulcsot. Ez azt jelentette, hogy egy lekérdezéstípust használtak kulcsok nélküli entitástípusok leképezéséhez (nagyobb valószínűséggel egy nézetben, de valószínűleg egy táblából), míg a kulcs rendelkezésre állásakor egy normál entitástípust használtak (nagyobb valószínűséggel egy táblából, de valószínűleg egy nézetből).
Új viselkedés
A lekérdezéstípusok mostantól csak egy elsődleges kulcs nélküli entitástípussá válnak. A kulcs nélküli entitástípusok ugyanazokkal a funkciókkal rendelkeznek, mint a korábbi verziók lekérdezéstípusai.
Miért
Ez a módosítás a lekérdezéstípusok céljával kapcsolatos félreértések csökkentése érdekében történt. Konkrétan kulcs nélküli entitástípusokról van szó, és emiatt ezek eredendően csak olvashatók, de nem szabad őket kizárólag azért használni, mert egy entitástípusnak írásvédettnek kell lennie. Hasonlóképpen gyakran leképezik őket a nézetekre, de ez annak köszönhető, hogy a nézetek gyakran nem határoznak meg kulcsokat.
Enyhítési intézkedések
Az API következő részei elavultak:
-
ModelBuilder.Query<>()
– Ehelyett egy entitástípus kulcs nélküliként való megjelöléséhezModelBuilder.Entity<>().HasNoKey()
kell meghívni. Ez továbbra sem kerül konvenció szerint konfigurálásra, hogy elkerüljük a helytelen konfigurációt, amikor elsődleges kulcs szükséges, de nem felel meg a konvenció elvárásainak. -
DbQuery<>
– EhelyettDbSet<>
kell használni. -
DbContext.Query<>()
– EhelyettDbContext.Set<>()
kell használni. -
IQueryTypeConfiguration<TQuery>
– EhelyettIEntityTypeConfiguration<TEntity>
kell használni.
Jegyzet
A probléma miatt a 3.x verziójában, amikor olyan kulcs nélküli entitásokat kérdezünk le, amelyek minden tulajdonsága null
, egy null
-et ad vissza egy entitás helyett. Ha ez a probléma az ön forgatókönyvére is vonatkozik, adjon hozzá logikát az eredményekben való null
kezelésére.
Módosult a konfigurációs API a saját típusú kapcsolatokhoz
követési probléma #12444követési probléma #9148követési probléma #14153
Régi viselkedés
Az EF Core 3.0 előtt a tulajdonosi kapcsolat konfigurálása közvetlenül a OwnsOne
vagy OwnsMany
hívás után történt.
Új viselkedés
Az EF Core 3.0-tól kezdve mostantól folyékony API-val konfigurálhat egy navigációs tulajdonságot a tulajdonosnak a WithOwner()
használatával.
Például:
modelBuilder.Entity<Order>.OwnsOne(e => e.Details).WithOwner(e => e.Order);
A tulajdonos és a tulajdonolt közötti kapcsolatra vonatkozó konfigurációt a többi kapcsolat konfigurálásához hasonlóan WithOwner()
után kell láncolni.
Miközben a saját típus konfigurációja továbbra is láncolva marad OwnsOne()/OwnsMany()
után.
Például:
modelBuilder.Entity<Order>.OwnsOne(e => e.Details, eb =>
{
eb.WithOwner()
.HasForeignKey(e => e.AlternateId)
.HasConstraintName("FK_OrderDetails");
eb.ToTable("OrderDetails");
eb.HasKey(e => e.AlternateId);
eb.HasIndex(e => e.Id);
eb.HasOne(e => e.Customer).WithOne();
eb.HasData(
new OrderDetails
{
AlternateId = 1,
Id = -1
});
});
A Entity()
, HasOne()
vagy Set()
saját típusú célként való meghívása mostantól kivételt fog eredményezni.
Miért
Ez a módosítás tisztább elkülönítést hozott létre a saját típus konfigurálása és a saját típushoz fűződő kapcsolat között.
Ez viszont megszünteti a kétértelműséget és zavart az olyan módszerek körül, mint a HasForeignKey
.
Enyhítések
Módosítsa a saját típusú kapcsolatok konfigurációját az új API-felület használatára a fenti példában látható módon.
A fő entitással táblát megosztó függő entitások mostantól választhatók
Nyomon követési probléma #9005
Régi viselkedés
Vegye figyelembe a következő modellt:
public class Order
{
public int Id { get; set; }
public int CustomerId { get; set; }
public OrderDetails Details { get; set; }
}
public class OrderDetails
{
public int Id { get; set; }
public string ShippingAddress { get; set; }
}
Az EF Core 3.0 előtt, ha OrderDetails
Order
tulajdonában van, vagy kifejezetten ugyanarra a táblára van leképezve, akkor mindig szükség volt egy OrderDetails
-példányra egy új Order
hozzáadásakor.
Új viselkedés
A 3.0-tól kezdve az EF Core lehetővé teszi Order
hozzáadását OrderDetails
nélkül, és leképezi az összes OrderDetails
tulajdonságot, kivéve az elsődleges kulcsot null értékű oszlopokra.
Az EF Core-készletek lekérdezése során OrderDetails
null
, ha a szükséges tulajdonságai közül bármelyiknek nincs értéke, vagy ha az elsődleges kulcson kívül egyáltalán nincsenek kötelező tulajdonságai, és az összes tulajdonság null
.
Enyhítő intézkedések
Ha a modell táblázatmegosztással rendelkezik az összes választható oszloptól függően, de a rá mutató navigáció várhatóan nem lesz null
, akkor az alkalmazást módosítani kell, hogy kezelje azokat az eseteket, amikor a navigáció null
. Ha ez nem lehetséges, egy kötelező tulajdonságot kell hozzáadni az entitástípushoz, vagy legalább egy tulajdonsághoz hozzá kell rendelni egy nemnull
értéket.
Az összes entitásnak, amelyik egy táblát oszt meg egy egyidejűségi token oszlopával, tulajdonsághoz kell rendelnie azt.
nyomon követési probléma #14154
Régi viselkedés
Vegye figyelembe a következő modellt:
public class Order
{
public int Id { get; set; }
public int CustomerId { get; set; }
public byte[] Version { get; set; }
public OrderDetails Details { get; set; }
}
public class OrderDetails
{
public int Id { get; set; }
public string ShippingAddress { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>()
.Property(o => o.Version).IsRowVersion().HasColumnName("Version");
}
EF Core 3.0 előtt, ha OrderDetails
Order
tulajdonában van, vagy kifejezetten ugyanarra a táblára van leképezve, akkor a csak OrderDetails
frissítése nem frissíti a Version
értéket az ügyfélnél, és a következő frissítés meghiúsul.
Új viselkedés
3.0-tól kezdődően az EF Core a Version
új értékét propagálja Order
-re, amennyiben az OrderDetails
tulajdonosa. Ellenkező esetben kivétel történik a modell érvényesítése során.
Miért
Ezt a módosítást azért hajtották végre, hogy elkerülje az elavult egyidejűségi token értékének problémáját, amikor csak az ugyanazon táblához hozzárendelt entitások egyikét frissítik.
Enyhítő intézkedések
A táblát megosztó összes entitásnak tartalmaznia kell egy tulajdonságot, amely az egyidejűségi jogkivonat oszlopára van leképezve. Lehetséges egy ilyet létrehozni árnyékállapotban.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<OrderDetails>()
.Property<byte[]>("Version").IsRowVersion().HasColumnName("Version");
}
A tulajdonos entitásai nem kérdezhetők le anélkül, hogy a tulajdonos nyomkövetési lekérdezést használ
nyomon követési probléma #18876
Régi viselkedés
Az EF Core 3.0 előtt a tulajdonolt entitások bármely más navigációhoz hasonlóan lekérdezhetők voltak.
context.People.Select(p => p.Address);
Új viselkedés
3.0-tól az EF Core hibát dob, ha egy nyomkövetési lekérdezés egy saját entitást projektál a tulajdonos nélkül.
Miért
A tulajdonban lévő entitások nem módosíthatók a tulajdonos nélkül, ezért az esetek túlnyomó többségében az ilyen módon történő lekérdezés hiba.
Enyhítések
Ha a tulajdonos entitást később bármilyen módon módosítani kell, akkor a tulajdonosnak szerepelnie kell a lekérdezésben.
Egyéb esetben adjon hozzá egy AsNoTracking()
hívást:
context.People.Select(p => p.Address).AsNoTracking();
A nem megfeleltetett típusok örökölt tulajdonságai mostantól egyetlen oszlopra vannak leképezve az összes származtatott típushoz
nyomon követési probléma #13998
Régi viselkedés
Vegye figyelembe a következő modellt:
public abstract class EntityBase
{
public int Id { get; set; }
}
public abstract class OrderBase : EntityBase
{
public int ShippingAddress { get; set; }
}
public class BulkOrder : OrderBase
{
}
public class Order : OrderBase
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Ignore<OrderBase>();
modelBuilder.Entity<EntityBase>();
modelBuilder.Entity<BulkOrder>();
modelBuilder.Entity<Order>();
}
Az EF Core 3.0 előtt a ShippingAddress
tulajdonság alapértelmezés szerint a BulkOrder
és Order
oszlopainak elkülönítésére lesz leképezve.
Új viselkedés
A 3.0 verziótól kezdve az EF Core csak egy oszlopot hoz létre ShippingAddress
esetében.
Miért
A régi viselkedés váratlan volt.
Enyhítések
A tulajdonság továbbra is explicit módon leképezhető a származtatott típusok külön oszlopára:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Ignore<OrderBase>();
modelBuilder.Entity<EntityBase>();
modelBuilder.Entity<BulkOrder>()
.Property(o => o.ShippingAddress).HasColumnName("BulkShippingAddress");
modelBuilder.Entity<Order>()
.Property(o => o.ShippingAddress).HasColumnName("ShippingAddress");
}
Az idegenkulcs-tulajdonság konvenciója már nem egyezik meg a főtulajdonság nevével
nyomon követési probléma #13274
Régi viselkedés
Vegye figyelembe a következő modellt:
public class Customer
{
public int CustomerId { get; set; }
public ICollection<Order> Orders { get; set; }
}
public class Order
{
public int Id { get; set; }
public int CustomerId { get; set; }
}
Az EF Core 3.0 előtt a CustomerId
tulajdonság konvenció szerint a külső kulcshoz lesz használva.
Ha azonban a Order
egy saját tulajdonú típus, akkor ez a CustomerId
-et is elsődleges kulccsá teszi, és ez általában nem az elvárás.
Új viselkedés
A 3.0-tól kezdődően az EF Core nem próbálja konvenció szerint használni az idegen kulcsok tulajdonságait, ha a név megegyezik a főtulajdonság nevével. A fő típusnév és a fő tulajdonságnév összefűzése, valamint a navigációs név és a fő tulajdonságnév összefűzése mintamódon továbbra is illeszkedik egymáshoz. Például:
public class Customer
{
public int Id { get; set; }
public ICollection<Order> Orders { get; set; }
}
public class Order
{
public int Id { get; set; }
public int CustomerId { get; set; }
}
public class Customer
{
public int Id { get; set; }
public ICollection<Order> Orders { get; set; }
}
public class Order
{
public int Id { get; set; }
public int BuyerId { get; set; }
public Customer Buyer { get; set; }
}
Miért
Ez a módosítás azért történt, hogy elkerülje egy elsődleges kulcstulajdonság hibás definiálását a saját típuson.
Enyhítések
Ha a tulajdonságot idegen kulcsnak szándékozták, és ezáltal az elsődleges kulcs részévé válna, akkor azt konkrétan így állítsa be.
Az adatbázis-kapcsolat bezárul, ha már nincs használatban, mielőtt a TransactionScope befejeződik
Régi viselkedés
Az EF Core 3.0 előtt, ha a környezet megnyitja a kapcsolatot egy TransactionScope
belül, a kapcsolat nyitva marad, amíg az aktuális TransactionScope
aktív.
using (new TransactionScope())
{
using (AdventureWorks context = new AdventureWorks())
{
context.ProductCategories.Add(new ProductCategory());
await context.SaveChangesAsync();
// Old behavior: Connection is still open at this point
var categories = await context.ProductCategories().ToListAsync();
}
}
Új viselkedés
A 3.0-stól kezdve az EF Core azonnal bezárja a kapcsolatot, amint elkészült a használatával.
Miért
Ez a módosítás lehetővé teszi több környezet használatát ugyanazon TransactionScope
-ban. Az új viselkedés az EF6-nak is megfelel.
Enyhítések
Ha a kapcsolatnak nyitva kell maradnia, akkor egy explicit hívás OpenConnection()
-ra biztosítja, hogy az EF Core ne zárja be idő előtt.
using (new TransactionScope())
{
using (AdventureWorks context = new AdventureWorks())
{
await context.Database.OpenConnectionAsync();
context.ProductCategories.Add(new ProductCategory());
await context.SaveChangesAsync();
var categories = await context.ProductCategories().ToListAsync();
await context.Database.CloseConnectionAsync();
}
}
Minden tulajdonság független memórián belüli egész szám kulcsgenerálást használ
Régi viselkedés
Az EF Core 3.0 előtt egy megosztott értékgenerátort használtunk az összes memóriabeli egész szám kulcstulajdonságához.
Új viselkedés
Az EF Core 3.0-tól kezdve minden egész szám kulcstulajdonság saját értékgenerátort kap a memóriabeli adatbázis használatakor. Ha az adatbázist törlik, a kulcsgenerálás minden táblához alaphelyzetbe áll.
Miért
Ezt a módosítást azért hajtották végre, hogy a memóriabeli kulcsok generációját jobban igazítsa a valós adatbáziskulcs-generációhoz, és hogy jobban elkülönítse egymástól a teszteket a memóriában lévő adatbázis használatakor.
Enyhítő intézkedések
Ez megszakíthatja azokat az alkalmazásokat, amelyek meghatározott memóriabeli kulcsértékekre támaszkodnak. Fontolja meg inkább, hogy ne támaszkodjon adott kulcsértékekre, vagy frissítsen az új viselkedésnek megfelelően.
A háttérmezők alapértelmezés szerint használhatók
Régi viselkedés
A 3.0 előtt, még ha egy tulajdonság háttérmezője is ismert volt, az EF Core továbbra is alapértelmezés szerint beolvassa és megírja a tulajdonság értékét a tulajdonság getter és a setter metódusok használatával. Ez alól kivételt képez a lekérdezés végrehajtása, ahol a háttérmezőt közvetlenül beállítják, ha ismert az érték.
Új viselkedés
Az EF Core 3.0-tól kezdődően, ha egy tulajdonság háttérmezője ismert, akkor az EF Core mindig a háttérmező használatával olvassa és írja meg ezt a tulajdonságot. Ez alkalmazástörést okozhat, ha az alkalmazás a getter vagy a setter metódusokba kódolt további viselkedésre támaszkodik.
Miért
Ez a módosítás megakadályozta, hogy az EF Core alapértelmezés szerint tévesen aktiválja az üzleti logikát az entitásokat érintő adatbázis-műveletek végrehajtásakor.
Enyhítések
A 3.0 előtti viselkedés a ModelBuilder
tulajdonságelérési módjának konfigurálásával állítható vissza.
Például:
modelBuilder.UsePropertyAccessMode(PropertyAccessMode.PreferFieldDuringConstruction);
Dobás, ha több kompatibilis háttérmező található
nyomon követési probléma #12523
Régi viselkedés
Az EF Core 3.0 előtt, ha egy tulajdonság háttérmezőjének megkeresésére vonatkozó szabályoknak több mező is megfelel, akkor egy mező lesz kiválasztva valamilyen elsőbbségi sorrend alapján. Ez azt okozhatja, hogy nem a megfelelő mezőt használja kétértelmű esetekben.
Új viselkedés
Az EF Core 3.0-tól kezdve, ha több mező is egyezik ugyanahhoz a tulajdonsághoz, kivételt eredményez.
Miért
Ezt a módosítást azért hajtották végre, hogy ne használjon csendben egy mezőt a másikon, ha csak egy lehet helyes.
Enyhítő intézkedések
A nem egyértelmű háttérmezőkkel rendelkező tulajdonságoknak a mezőt kifejezetten meg kell adniuk. Például a fluent API használatával:
modelBuilder
.Entity<Blog>()
.Property(e => e.Id)
.HasField("_id");
A csak mezőre vonatkozó tulajdonságneveknek meg kell egyeznie a mező nevével
Régi viselkedés
Az EF Core 3.0 előtt egy tulajdonságot sztringértékkel lehet megadni, és ha a .NET-típusban nem található ilyen nevű tulajdonság, akkor az EF Core konvenciós szabályokkal próbálja meg egy mezőhöz igazítani.
private class Blog
{
private int _id;
public string Name { get; set; }
}
modelBuilder
.Entity<Blog>()
.Property("Id");
Új viselkedés
Az EF Core 3.0-tól kezdve egy csak mezőre vonatkozó tulajdonságnak pontosan meg kell egyeznie a mező nevével.
modelBuilder
.Entity<Blog>()
.Property("_id");
Miért
Ezt a módosítást azért hajtották végre, hogy ne használja ugyanazt a mezőt két hasonló nevű tulajdonsághoz, és a csak mezőtulajdonságokra vonatkozó egyező szabályokat is ugyanazsá teszi, mint a CLR-tulajdonságokra leképezett tulajdonságok esetében.
Enyhítő intézkedések
A csak mező típusú tulajdonságokat ugyanúgy kell elnevezni, mint a hozzárendelt mezőt. Az EF Core 3.0 utáni jövőbeni kiadásában a tulajdonság nevétől eltérő mezőnév explicit konfigurálását tervezzük újra engedélyezni (lásd: #15307):
modelBuilder
.Entity<Blog>()
.Property("Id")
.HasField("_id");
Az AddDbContext/AddDbContextPool már nem hívja meg az AddLogging és az AddMemoryCache függvényt
Régi viselkedés
Az EF Core 3.0 előtt a AddDbContext
vagy AddDbContextPool
hívása a naplózási és memória gyorsítótárazási szolgáltatásokat is regisztrálta a DI-vel az AddLogging és AddMemoryCachehívásokon keresztül.
Új viselkedés
Az EF Core 3.0-tól kezdődően AddDbContext
és AddDbContextPool
már nem fogja regisztrálni ezeket a szolgáltatásokat a dependencia injektálás (DI) keretében.
Miért
Az EF Core 3.0 nem követeli meg, hogy ezek a szolgáltatások az alkalmazás DI-tárolójában legyenek. Ha azonban ILoggerFactory
regisztrálva van az alkalmazás DI-tárolójában, akkor az EF Core továbbra is használni fogja.
Csökkentő intézkedések
Ha az alkalmazásnak szüksége van ezekre a szolgáltatásokra, regisztrálja őket explicit módon a DI-tárolóban AddLogging vagy AddMemoryCachehasználatával.
Az AddEntityFramework* méretkorláttal rendelkező IMemoryCache-t ad hozzá
nyomon követési probléma #12905
Régi viselkedés
Az EF Core 3.0 előtt a AddEntityFramework*
metódusok meghívása a memória-gyorsítótárazási szolgáltatásokat is regisztrálná a DI-ben méretkorlát nélkül.
Új viselkedés
Az EF Core 3.0-tól kezdve a AddEntityFramework*
egy méretkorláttal rendelkező IMemoryCache szolgáltatást regisztrál. Ha a későbbiekben hozzáadott egyéb szolgáltatások az IMemoryCache függvénytől függenek, gyorsan elérhetik az alapértelmezett korlátot, ami kivételeket vagy teljesítménycsökkenést okoz.
Miért
Ha az IMemoryCache korlát nélkül használ, az ellenőrizetlen memóriahasználatot eredményezhet, ha hiba van a lekérdezés gyorsítótárazási logikájában, vagy ha a lekérdezések dinamikusan jönnek létre. Az alapértelmezett korlát csökkenti a dos-támadásokat.
Enyhítések
A legtöbb esetben nem szükséges meghívni AddEntityFramework*
, ha AddDbContext
vagy AddDbContextPool
is meghívják. Ezért a legjobb megoldás az AddEntityFramework*
hívás eltávolítása.
Ha az alkalmazásnak szüksége van ezekre a szolgáltatásokra, akkor előzetesen regisztráljon egy IMemoryCache-implementációt a DI-tárolóban az AddMemoryCachehasználatával.
A DbContext.Entry mostantól helyi DetectChanges-műveletet hajt végre
nyomon követési probléma #13552
Régi viselkedés
Az EF Core 3.0 előtt a DbContext.Entry
hívása az összes követett entitás esetében változásokat okozna.
Ez biztosította, hogy a EntityEntry
-ban megjelenített állapot a up-to-nek megfelelő legyen, a megfelelő dátummal.
Új viselkedés
Az EF Core 3.0-tól kezdve a DbContext.Entry
hívása mostantól csak az adott entitás és az ahhoz kapcsolódó nyomon követett fő entitások változásait kísérli meg észlelni.
Ez azt jelenti, hogy a metódus meghívásával máshol nem észlelhetők változások, ami hatással lehet az alkalmazás állapotára.
Vegye figyelembe, hogy ha ChangeTracker.AutoDetectChangesEnabled
false
van beállítva, akkor még a helyi változásészlelés is le lesz tiltva.
A változásészlelést okozó egyéb módszerek – például ChangeTracker.Entries
és SaveChanges
– továbbra is okozzák az összes követett entitás teljes DetectChanges
.
Miért
Ez a módosítás a context.Entry
alapértelmezett teljesítményének javítása érdekében történt.
Enyhítések
Az elő-3.0 viselkedés biztosítása érdekében hívja meg kifejezetten a ChangeTracker.DetectChanges()
-t, mielőtt a Entry
-et hívná meg.
A sztring- és bájttömbkulcsok alapértelmezés szerint nem ügyfél által generáltak
nyomon követési probléma #14617
Régi viselkedés
Az EF Core 3.0 előtt string
és byte[]
kulcstulajdonságok használhatók anélkül, hogy explicit módon nem null értéket adna meg.
Ilyen esetben a kulcsérték globálisan egyedi azonosítóként (GUID) jön létre az ügyfélen, és bájtokba van szerializálva a byte[]
számára.
Új viselkedés
Az EF Core 3.0-tól kezdve kivétel jelenik meg, amely azt jelzi, hogy nincs megadva kulcsérték.
Miért
Ez a módosítás azért történt, mert az ügyfél által generált string
/byte[]
értékek általában nem hasznosak, és az alapértelmezett viselkedés megnehezítette a generált kulcsértékek általános okát.
Enyhítések
A 3.0 előtti viselkedést úgy lehet elérni, hogy explicit módon megadhatja, hogy a kulcstulajdonságok generált értékeket használjanak, ha nincs más nem null érték beállítva. Például a fluent API-val:
modelBuilder
.Entity<Blog>()
.Property(e => e.Id)
.ValueGeneratedOnAdd();
Vagy adatjegyzetekkel:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }
Az ILoggerFactory mostantól egy hatókörön belüli szolgáltatás.
nyomon követési probléma #14698
Régi viselkedés
Az EF Core 3.0 előtt ILoggerFactory
egyszeri szolgáltatásként lett regisztrálva.
Új viselkedés
Az EF Core 3.0-tól kezdve a ILoggerFactory
mostantól hatókörként van regisztrálva.
Miért
Ezen módosítás célja, hogy lehetővé tegye egy naplózó társítását egy DbContext
-példányhoz, amely aktivál más funkciókat, és eltávolít egyes korábban tapasztalt patológiás viselkedési eseteket, például a belső szolgáltatók túlburjánzását.
Enyhítések
Ez a módosítás csak akkor érinti az alkalmazáskódot, ha egyéni szolgáltatásokat regisztrál és használ az EF Core belső szolgáltatóján.
Ez nem gyakori.
Ezekben az esetekben a legtöbb dolog továbbra is működni fog, de a ILoggerFactory
-tól függő egyetlen példányú szolgáltatásokat módosítani kell, hogy a ILoggerFactory
-et más módon szerezhessék be.
Ha ilyen helyzetekbe ütközik, kérjük, jelentsen be egy hibát a EF Core GitHub problémakövetőn, hogy tudassuk, Ön hogyan használja a ILoggerFactory
, és ennek megértésével biztosíthassuk, hogy a jövőben ne okozzunk hasonló problémát.
A lazy-loading proxyk már nem feltételezik a navigációs tulajdonságok teljes betöltését
Régi viselkedés
Az EF Core 3.0 előtt, miután egy DbContext
el lett távolítva, nem lehetett tudni, hogy az adott navigációs tulajdonság teljes mértékben betöltődött-e az adott környezetből beszerzett entitáson.
A proxyk ehelyett azt feltételezik, hogy a hivatkozásnavigáció betöltődik, ha nem null értékű, és ha nem üres, akkor a gyűjteménynavigáció betöltődik.
Ezekben az esetekben a lassú betöltés megkísérlése no-oplenne.
Új viselkedés
Az EF Core 3.0-tól kezdve a proxyk nyomon követik, hogy egy navigációs tulajdonság be van-e töltve. Ez azt jelenti, hogy a környezet törlése után betöltött navigációs tulajdonság elérése mindig no-oplesz, még akkor is, ha a betöltött navigáció üres vagy null értékű. Ezzel szemben, ha megpróbálunk elérni egy nem betöltött navigációs tulajdonságot, az kivételt okoz, ha a kontextus be van zárva, még akkor is, ha a navigációs tulajdonság nem üres gyűjtemény. Ha ez a helyzet áll fenn, az azt jelenti, hogy az alkalmazáskód a lusta betöltést próbálja meg használni érvénytelen időpontban, és az alkalmazást úgy kell módosítani, hogy ne tegye ezt meg.
Miért
Ez a módosítás konzisztenssé és helyessé tette a viselkedést egy eldobott DbContext
példány lusta betöltésekor.
Enyhítések
Frissítse az alkalmazás kódját úgy, hogy ne próbáljon meg halasztott betöltést egy elvetett kontextussal, vagy konfigurálja ezt no-op státuszra a kivételüzenetben leírtak szerint.
A belső szolgáltatók túlzott létrehozása alapértelmezés szerint hiba
nyomon követési probléma #10236
Régi viselkedés
Az EF Core 3.0 előtt a rendszer figyelmeztetést naplóz egy olyan alkalmazáshoz, amely patológiás számú belső szolgáltatót hoz létre.
Új viselkedés
Az EF Core 3.0-tól kezdve ezt a figyelmeztetést hibaként kezelik, és kivételt dob.
Miért
Ezt a módosítást úgy hajtották végre, hogy a patológiás eset pontosabb feltárásával jobb alkalmazáskódot vezessen be.
Enyhítések
A hiba elhárításának legmegfelelőbb oka a kiváltó ok megismerése és ennyi belső szolgáltató létrehozásának leállítása.
A hiba azonban visszakonfigurálható figyelmeztetéssé (vagy figyelmen kívül hagyhatóvá) a DbContextOptionsBuilder
konfigurációján keresztül.
Például:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.ConfigureWarnings(w => w.Log(CoreEventId.ManyServiceProvidersCreatedWarning));
}
A HasOne/HasMany új viselkedése, ha egyetlen karakterlánccal van meghívva
Nyomon Követési Probléma #9171
Régi viselkedés
Az EF Core 3.0 előtt a HasOne
vagy HasMany
egyetlen karakterlánccal való meghívását zavaró módon értelmezték.
Például:
modelBuilder.Entity<Samurai>().HasOne("Entrance").WithOne();
A kód úgy tűnik, hogy Samurai
valamilyen más entitástípushoz kapcsolódik a Entrance
navigációs tulajdonság használatával, amely lehet privát.
A valóságban ez a kód egy Entrance
nevű entitástípushoz próbál kapcsolatot létrehozni navigációs tulajdonság nélkül.
Új viselkedés
Az EF Core 3.0-tól kezdve a fenti kód most azt teszi, amit korábban kellett volna.
Miért
A régi viselkedés nagyon zavaró volt, különösen a konfigurációs kód olvasásakor és a hibák keresésekor.
Enyhítése
Ez csak azokat az alkalmazásokat szakítja meg, amelyek a kapcsolatok típusneveihez való konfigurálását karakterláncok használatával végzik, a navigációs tulajdonság explicit megadása nélkül.
Ez nem gyakori.
Az előző viselkedés úgy érhető el, ha a navigációs tulajdonság nevét explicit módon null
-ként adjuk meg.
Például:
modelBuilder.Entity<Samurai>().HasOne("Some.Entity.Type.Name", null).WithOne();
Több aszinkron metódus visszatérési típusa tevékenységről ValueTask-ra módosult
nyomon követési probléma #15184
Régi viselkedés
A következő aszinkron metódusok korábban egy Task<T>
adták vissza:
DbContext.FindAsync()
DbSet.FindAsync()
DbContext.AddAsync()
DbSet.AddAsync()
-
ValueGenerator.NextValueAsync()
(és származtatási osztályok)
Új viselkedés
A fenti metódusok mostantól ugyanazon T
-re egy ValueTask<T>
-t adnak vissza, mint korábban.
Miért
Ez a változás csökkenti a módszerek meghívása során felmerülő halomfoglalások számát, és javítja az általános teljesítményt.
Megszorítások
Azoknak az alkalmazásoknak, amelyek csak a fent említett API-kra várnak, mindössze újra kell fordítani - nincs szükség forrásmódosításra.
Egy összetettebb használat (például a visszaadott Task
átadása Task.WhenAny()
-nek) általában megköveteli, hogy a visszaadott ValueTask<T>
-t Task<T>
-má kell alakítani a AsTask()
hívásával.
Vegye figyelembe, hogy ez semlegesíti a módosítás által eredményezett foglaláscsökkentést.
A Relational:TypeMapping annotáció most már csak TypeMapping
Régi viselkedés
A típusleképezési széljegyzetek széljegyzetneve a következő volt: "Relational:TypeMapping".
Új viselkedés
A típusleképezési széljegyzetek széljegyzetneve mostantól "TypeMapping".
Miért
A típusleképezések mostantól nem csupán relációs adatbázis-szolgáltatókhoz használhatók.
Enyhítési intézkedések
Ez csak olyan alkalmazásokat szakít meg, amelyek közvetlenül széljegyzetként férnek hozzá a típusleképezéshez, ami nem gyakori. A legmegfelelőbb lépés az, ha az API felületet használja a típusleképezések elérésére ahelyett, hogy közvetlenül az annotációt használná.
A származtatott típushoz tartozó ToTable metódus kivételt dob
nyomon követési probléma #11811
Régi viselkedés
Az EF Core 3.0 előtt a rendszer figyelmen kívül hagyja a származtatott típus ToTable()
meghívását, mivel csak az öröklés-leképezési stratégia volt TPH, ahol ez nem érvényes.
Új viselkedés
Az EF Core 3.0-tól kezdve, valamint a TPT- és TPC-támogatás későbbi kiadásban való hozzáadásának előkészítésekor ToTable()
származtatott típust hív meg, kivételt jelent, hogy a jövőben elkerülhető legyen a váratlan leképezési változás.
Miért
Jelenleg nem lehetséges egy származtatott típust egy másik táblára képezni. Ez a változtatás megelőzi a jövőbeli hibákat, amikor ez az érvényes eljárás.
Mitigálások
Távolítsa el a származtatott típusok más táblákra való leképezésére tett kísérleteket.
ForSqlServerHasIndex helyett HasIndex
nyomon követési probléma #12366
Régi viselkedés
Az EF Core 3.0 előtt ForSqlServerHasIndex().ForSqlServerInclude()
lehetővé tette a INCLUDE
által használt oszlopok konfigurálását.
Új viselkedés
Az EF Core 3.0-tól kezdve az index Include
használata mostantól relációs szinten támogatott.
Használja a HasIndex().ForSqlServerInclude()
.
Miért
Ez a módosítás azért történt, hogy az összes adatbázis-szolgáltató számára a Include
azonosítójú indexek API-ját egy helyre összesítsék.
Enyhítése
Használja az új API-t a fent látható módon.
Metadata API-módosítások
Új viselkedés
A következő tulajdonságok bővítménymetelyekké lettek konvertálva:
-
IEntityType.QueryFilter
–>GetQueryFilter()
-
IEntityType.DefiningQuery
–>GetDefiningQuery()
-
IProperty.IsShadowProperty
–>IsShadowProperty()
-
IProperty.BeforeSaveBehavior
–>GetBeforeSaveBehavior()
-
IProperty.AfterSaveBehavior
–>GetAfterSaveBehavior()
Miért
Ez a változás leegyszerűsíti a fent említett interfészek megvalósítását.
Enyhítések
Használja az új kiterjesztési módszereket.
Szolgáltatóspecifikus Metadata API-módosítások
Új viselkedés
A szolgáltatóspecifikus bővítménymetódusok össze lesznek vonva.
-
IProperty.Relational().ColumnName
–>IProperty.GetColumnName()
-
IEntityType.SqlServer().IsMemoryOptimized
–>IEntityType.IsMemoryOptimized()
-
PropertyBuilder.UseSqlServerIdentityColumn()
–>PropertyBuilder.UseIdentityColumn()
Miért
Ez a módosítás leegyszerűsíti a fent említett kiterjesztési módszerek végrehajtását.
Enyhítése
Használja az új kiterjesztési metódusokat.
Az EF Core már nem küld pragmát az SQLite FK-kényszerítéshez
Nyomon követési probléma #12151
Régi viselkedés
Az EF Core 3.0 előtt az EF Core PRAGMA foreign_keys = 1
küld az SQLite-hez való kapcsolat megnyitásakor.
Új viselkedés
Az EF Core 3.0-tól kezdve az EF Core már nem küld PRAGMA foreign_keys = 1
az SQLite-hez való kapcsolat megnyitásakor.
Miért
Ez a módosítás azért történt, mert az EF Core alapértelmezés szerint SQLitePCLRaw.bundle_e_sqlite3
használ, ami azt jelenti, hogy az FK-kényszerítés alapértelmezés szerint be van kapcsolva, és nem kell explicit módon engedélyezni a kapcsolat minden egyes megnyitásakor.
Enyhítések
A külső kulcsok a SQLitePCLRaw.bundle_e_sqlite3-ban vannak alapértelmezetten engedélyezve, amely az EF Core számára van alapértelmezetten használva.
Más esetekben az idegen kulcsok engedélyezhetők Foreign Keys=True
megadásával a kapcsolati sztringben.
A Microsoft.EntityFrameworkCore.Sqlite mostantól az SQLitePCLRaw.bundle_e_sqlite3-től függ.
Régi viselkedés
Az EF Core 3.0 előtt az EF Core SQLitePCLRaw.bundle_green
használt.
Új viselkedés
Az EF Core 3.0-tól kezdve az EF Core SQLitePCLRaw.bundle_e_sqlite3
használ.
Miért
Ezt a módosítást úgy hajtották végre, hogy az iOS-en használt SQLite verziója konzisztens legyen más platformokkal.
Mérséklések
Az iOS natív SQLite-verziójának használatához konfigurálja a Microsoft.Data.Sqlite
egy másik SQLitePCLRaw
csomag használatára.
A guid értékek mostantól szövegként vannak tárolva az SQLite-en
Nyomon követési probléma #15078
Régi viselkedés
A guid értékek korábban BLOB-értékekként lettek tárolva az SQLite-ben.
Új viselkedés
A guid értékek mostantól SZÖVEGként vannak tárolva.
Miért
A guidok bináris formátuma nem szabványosított. Az értékek TEXT formátumban való tárolása az adatbázist kompatibilisebbé teszi más technológiákkal.
Enyhítések
A meglévő adatbázisokat az alábbihoz hasonlóan az SQL futtatásával migrálhatja az új formátumba.
UPDATE MyTable
SET GuidColumn = hex(substr(GuidColumn, 4, 1)) ||
hex(substr(GuidColumn, 3, 1)) ||
hex(substr(GuidColumn, 2, 1)) ||
hex(substr(GuidColumn, 1, 1)) || '-' ||
hex(substr(GuidColumn, 6, 1)) ||
hex(substr(GuidColumn, 5, 1)) || '-' ||
hex(substr(GuidColumn, 8, 1)) ||
hex(substr(GuidColumn, 7, 1)) || '-' ||
hex(substr(GuidColumn, 9, 2)) || '-' ||
hex(substr(GuidColumn, 11, 6))
WHERE typeof(GuidColumn) == 'blob';
Az EF Core-ban az előző viselkedést is használhatja egy értékkonverter konfigurálásával ezeken a tulajdonságokon.
modelBuilder
.Entity<MyEntity>()
.Property(e => e.GuidProperty)
.HasConversion(
g => g.ToByteArray(),
b => new Guid(b));
A Microsoft.Data.Sqlite továbbra is képes a GUID értékek blob- és SZÖVEGoszlopokból való olvasására; Mivel azonban a paraméterek és az állandók alapértelmezett formátuma megváltozott, valószínűleg a legtöbb guidot tartalmazó forgatókönyv esetében kell műveletet elvégeznie.
A karakterértékek mostantól SZÖVEGként vannak tárolva az SQLite-ben
Régi viselkedés
A karakterértékek korábban egész számként lettek tárolva az SQLite-ben. Egy
Új viselkedés
A karakterértékek mostantól SZÖVEGként vannak tárolva.
Miért
Az értékek TEXT formátumban való tárolása természetesebb, és kompatibilisebbé teszi az adatbázist más technológiákkal.
Ellenintézkedések
A meglévő adatbázisokat az alábbihoz hasonlóan az SQL futtatásával migrálhatja az új formátumba.
UPDATE MyTable
SET CharColumn = char(CharColumn)
WHERE typeof(CharColumn) = 'integer';
Az EF Core-ban az előző viselkedést is használhatja egy értékkonverter konfigurálásával ezeken a tulajdonságokon.
modelBuilder
.Entity<MyEntity>()
.Property(e => e.CharProperty)
.HasConversion(
c => (long)c,
i => (char)i);
A Microsoft.Data.Sqlite képes az EGÉSZ és a SZÖVEG oszlop karakterértékeinek olvasására is, így bizonyos forgatókönyvek nem igényelnek semmilyen műveletet.
A migrálási azonosítók mostantól az invariáns kultúra naptárával jönnek létre
Régi viselkedés
A migrálási azonosítók véletlenül az aktuális kultúra naptárával lettek létrehozva.
Új viselkedés
A migrálási azonosítók mostantól mindig az invariáns kultúra naptárával (Gergely-naptár) jönnek létre.
Miért
Az áttelepítések sorrendje fontos az adatbázis frissítésekor vagy az egyesítési ütközések feloldásakor. Az invariáns naptár használata elkerüli a problémákat, amelyek abból adódhatnak, hogy a csapattagok különböző rendszernaptárakat használnak.
Enyhítések
Ez a változás mindenkit érint, aki nem Gergely-naptárt használ, ahol az év nagyobb, mint a Gergely-naptár (például a thai buddhista naptár). A meglévő migrálási azonosítókat frissíteni kell, hogy az új áttelepítések a meglévő áttelepítések után legyenek rendezve.
Az áttelepítési azonosító a Migrálás attribútumban található a migrálás tervezőfájljaiban.
[DbContext(typeof(MyDbContext))]
-[Migration("25620318122820_MyMigration")]
+[Migration("20190318122820_MyMigration")]
partial class MyMigration
{
A Migrálások előzménytáblát is frissíteni kell.
UPDATE __EFMigrationsHistory
SET MigrationId = CONCAT(LEFT(MigrationId, 4) - 543, SUBSTRING(MigrationId, 4, 150))
A UseRowNumberForPaging el lett távolítva
nyomon követési probléma #16400
Régi viselkedés
Az EF Core 3.0 előtt UseRowNumberForPaging
használható az SQL Server 2008-tal kompatibilis lapozási SQL létrehozásához.
Új viselkedés
Az EF Core 3.0-tól kezdve az EF csak olyan SQL-t hoz létre lapozáshoz, amely csak a későbbi SQL Server-verziókkal kompatibilis.
Miért
Ezt a módosítást azért hajtjuk végre, mert SQL Server 2008 már nem támogatott termék és a funkció frissítése az EF Core 3.0-ban végrehajtott lekérdezési módosításokhoz jelentős munka.
Mérsékelő intézkedések
Javasoljuk, hogy frissítsen az SQL Server újabb verziójára, vagy használjon magasabb kompatibilitási szintet, hogy a létrehozott SQL támogatott legyen. Ennek ellenére, ha nem tudja ezt megtenni, kérjük, megjegyzést a nyomon követési probléma a részletekkel. Visszajelzések alapján felülvizsgálhatjuk ezt a döntést.
A bővítményadatok/metaadatok el lettek távolítva az IDbContextOptionsExtension szolgáltatásból
Nyomon Követési Probléma #16119
Régi viselkedés
IDbContextOptionsExtension
tartalmazott metódusokat a bővítmény metaadatainak megadásához.
Új viselkedés
Ezek a metódusok át lettek helyezve egy új DbContextOptionsExtensionInfo
absztrakt alaposztályra, amely egy új IDbContextOptionsExtension.Info
tulajdonságból lesz visszaadva.
Miért
A 2.0-tól a 3.0-s verzióig több alkalommal kellett hozzáadni vagy módosítani ezeket a módszereket. Ha egy új absztrakt alaposztályra bontja őket, egyszerűbbé válik az ilyen jellegű módosítások végrehajtása a meglévő bővítmények feltörése nélkül.
Enyhítések
Frissítse a bővítményeket az új minta követéséhez.
A IDbContextOptionsExtension
számos implementációjában találhatók példák az EF Core-forráskód különböző típusú bővítményeihez.
Az LogQueryPossibleExceptionWithAggregateOperator át lett nevezve
nyomon követési probléma #10985
Változás
RelationalEventId.LogQueryPossibleExceptionWithAggregateOperator
átnevezték RelationalEventId.LogQueryPossibleExceptionWithAggregateOperatorWarning
.
Miért
A figyelmeztető esemény elnevezését az összes többi figyelmeztető eseményhez igazítja.
Enyhítések
Használja az új nevet. (Vegye figyelembe, hogy az eseményazonosító száma nem változott.)
Az API tisztázása idegenkulcs-kényszernevekhez
nyomon követési probléma #10730
Régi viselkedés
Az EF Core 3.0 előtt a külső kulcsok kényszernevét egyszerűen "névnek" nevezték. Például:
var constraintName = myForeignKey.Name;
Új viselkedés
Az EF Core 3.0-tól kezdve a külső kulcsok kényszernevét most "kényszernévnek" nevezzük. Például:
var constraintName = myForeignKey.ConstraintName;
Miért
Ez a módosítás konzisztenciát hoz az elnevezéshez ezen a területen, és azt is egyértelművé teszi, hogy ez az idegenkulcs-korlátozás neve, és nem az az oszlop vagy tulajdonságnév, amelyen az idegen kulcs van definiálva.
Enyhítések
Használja az új nevet.
Az IRelationalDatabaseCreator.HasTables/HasTablesAsync nyilvánossá lett téve
nyomon követési probléma #15997
Régi viselkedés
Az EF Core 3.0 előtt ezek a módszerek védettek voltak.
Új viselkedés
Az EF Core 3.0-tól kezdve ezek a módszerek nyilvánosak.
Miért
Ezeket a metódusokat az EF használja annak meghatározására, hogy létrejön-e adatbázis, de üres. Ez akkor is hasznos lehet az EF-n kívülről, ha eldönti, hogy alkalmazza-e a migrálásokat.
Enyhítések
Módosítsa a felülbírálások hozzáférhetőségét.
Microsoft.EntityFrameworkCore.Design mostantól egy DevelopmentDependency csomag
nyomon követési probléma #11506
Régi viselkedés
Az EF Core 3.0 előtt Microsoft.EntityFrameworkCore.Design egy szokásos NuGet-csomag volt, amelynek szerelvényére hivatkozni lehetett az attól függő projektekben.
Új viselkedés
Az EF Core 3.0-tól kezdve ez egy DevelopmentDependency csomag. Ez azt jelenti, hogy a függőség nem halad át tranzitív függőségként más projektekbe, és többé alapértelmezés szerint nem hivatkozhat az összeállítására.
Miért
Ez a csomag csak tervezéskor használható. Az üzembe helyezett alkalmazások nem hivatkoznak rá. A csomag fejlesztési függőségként való megjelölése megerősíti ezt az ajánlást.
Enyhítések
Ha hivatkoznia kell erre a csomagra az EF Core tervezési idejű viselkedésének felülbírálásához, akkor frissítheti a PackageReference elem metadatát a projektben.
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.0.0">
<PrivateAssets>all</PrivateAssets>
<!-- Remove IncludeAssets to allow compiling against the assembly -->
<!--<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>-->
</PackageReference>
Ha a csomagra tranzitív módon hivatkozik a Microsoft.EntityFrameworkCore.Tools segítségével, a metaadatok módosításához explicit PackageReference-t kell hozzáadnia a csomaghoz. Ilyen explicit hivatkozást kell hozzáadni minden olyan projekthez, ahol a csomag típusaira szükség van.
SQLitePCL.raw 2.0.0-s verzióra frissítve
nyomon követési probléma #14824
Régi viselkedés
A Microsoft.EntityFrameworkCore.Sqlite korábban a SQLitePCL.raw 1.1.12-es verziójától függött.
Új viselkedés
A csomagot úgy frissítettük, hogy a 2.0.0-s verziótól függjön.
Miért
A SQLitePCL.raw 2.0.0-s verziója a .NET Standard 2.0-s verzióját célozza. Korábban a .NET Standard 1.1-et célozta meg, amely a tranzitív csomagok nagy bezárását követelte meg.
Enyhítések
SQLitePCL.raw 2.0.0-s verzió néhány kompatibilitástörő módosítást tartalmaz. A részletekért tekintse meg a kibocsátási megjegyzéseit.
NetTopologySuite frissítve a 2.0.0-s verzióra
nyomon követési probléma #14825
Régi viselkedés
A térbeli csomagok korábban a NetTopologySuite 1.15.1-es verziójától függtek.
Új viselkedés
A csomagot úgy frissítettük, hogy a 2.0.0-s verziótól függjön.
Miért
A NetTopologySuite 2.0.0-s verziójának célja az EF Core-felhasználók által tapasztalt számos használhatósági probléma megoldása.
Enyhítések
A NetTopologySuite 2.0.0-s verziója kompatibilitástörő változásokat tartalmaz. A részletekért tekintse meg a kibocsátási megjegyzéseit.
A Rendszer.Data.SqlClient helyett a Microsoft.Data.SqlClient használatos
nyomon követési probléma #15636
Régi viselkedés
A Microsoft.EntityFrameworkCore.SqlServer korábban a System.Data.SqlClient függvénytől függött.
Új viselkedés
Frissítettük a csomagunkat, hogy a Microsoft.Data.SqlClient-től függjön.
Miért
A Microsoft.Data.SqlClient az SQL Server legfontosabb adatelérési illesztőprogramja, és a System.Data.SqlClient már nem a fejlesztés középpontjában áll. Néhány fontos funkció, például az Always Encrypted csak a Microsoft.Data.SqlClientben érhető el.
Enyhítések
Ha a kód közvetlen függőséget vesz fel a System.Data.SqlClient szolgáltatástól, módosítania kell, hogy inkább a Microsoft.Data.SqlClientre hivatkozzon; mivel a két csomag nagyon magas szintű API-kompatibilitást tart fenn, ez csak egy egyszerű csomag- és névtérmódosítás lehet.
Több nem egyértelmű önhivatkozási kapcsolatot kell konfigurálni
Nyomon Követési Probléma #13573
Régi viselkedés
A több önkiszolgáló, egyirányú navigációs tulajdonságokkal és egyező FK-kkal rendelkező entitástípus helytelenül lett konfigurálva egyetlen kapcsolatként. Például:
public class User
{
public Guid Id { get; set; }
public User CreatedBy { get; set; }
public User UpdatedBy { get; set; }
public Guid CreatedById { get; set; }
public Guid? UpdatedById { get; set; }
}
Új viselkedés
Ez a forgatókönyv már észlelhető a modellépítés során, és a rendszer kivételt jelez, amely azt jelzi, hogy a modell nem egyértelmű.
Miért
Az eredményül kapott modell nem egyértelmű volt, és valószínűleg ebben az esetben valószínűleg helytelen lesz.
Megelőző intézkedések
Használja a kapcsolat teljes konfigurációját. Például:
modelBuilder
.Entity<User>()
.HasOne(e => e.CreatedBy)
.WithMany();
modelBuilder
.Entity<User>()
.HasOne(e => e.UpdatedBy)
.WithMany();
A DbFunction.Schema, ha null vagy üres karakterlánc, úgy konfigurálódik, hogy a modell alapértelmezett sémájában legyen.
Régi viselkedés
A sémával üres sztringként konfigurált DbFunction beépített függvényként lett kezelve séma nélkül. Az alábbi kód például megfelelteti DatePart
CLR-függvényt az SqlServer beépített függvényének DATEPART
.
[DbFunction("DATEPART", Schema = "")]
public static int? DatePart(string datePartArg, DateTime? date) => throw new Exception();
Új viselkedés
Az összes DbFunction-leképezés felhasználó által definiált függvényekhez van megfeleltetve. Ezért az üres sztringérték a függvényt a modell alapértelmezett sémája közé helyezi. Ez lehet a fluent API-n keresztül explicit módon konfigurált séma, modelBuilder.HasDefaultSchema()
vagy különben dbo
.
Miért
A korábban üres séma volt a beépített függvény kezelésére szolgáló módszer, de ez a logika csak olyan SqlServer esetén alkalmazható, ahol a beépített függvények nem tartoznak semmilyen sémához.
Enyhítések
Konfigurálja manuálisan a DbFunction-hoz tartozó fordítást egy beépített függvényre való társításához.
modelBuilder
.HasDbFunction(typeof(MyContext).GetMethod(nameof(MyContext.DatePart)))
.HasTranslation(args => SqlFunctionExpression.Create("DatePart", args, typeof(int?), null));
EF Core 3.0 a .NET Standard 2.1-et célozza meg a .NET Standard 2.0 helyett, visszaállítva
Az EF Core 3.0 a .NET Standard 2.1-et célozza, ami egy olyan kompatibilitástörő változás, amely kizárja a .NET-keretrendszer-alkalmazásokat. Az EF Core 3.1 visszaállította ezt, és ismét a .NET Standard 2.0-t célozza meg.
A lekérdezés végrehajtása hibakeresési szintben rögzítve visszaállítva
nyomon követési probléma #14523
Ezt a módosítást visszaállítottuk, mert az EF Core 3.0 új konfigurációja lehetővé teszi, hogy az alkalmazás minden esemény naplószintje meg legyen adva. Például, ha az SQL naplózásának Debug
váltására van szükség, akkor explicit módon konfigurálja a szintet a OnConfiguring
-ben vagy AddDbContext
-ben.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseSqlServer(connectionString)
.ConfigureWarnings(c => c.Log((RelationalEventId.CommandExecuting, LogLevel.Debug)));