Belangrijke wijzigingen in EF Core 3.x
De volgende API- en gedragswijzigingen hebben het potentieel om bestaande toepassingen te verbreken bij het upgraden naar 3.x. Wijzigingen die we verwachten alleen van invloed te zijn op databaseproviders, worden gedocumenteerd onder providerwijzigingen.
Samenvatting
Wijzigingen met hoge impact
LINQ-query's worden niet meer geëvalueerd op de client
Probleem bijhouden #14935Zie ook probleem #12795
Oud gedrag
Voordat 3.0, wanneer EF Core een expressie die deel uitmaakte van een query niet kon converteren naar SQL of een parameter, werd de expressie automatisch op de client geëvalueerd. Standaard heeft clientevaluatie van mogelijk dure expressies alleen een waarschuwing geactiveerd.
Nieuw gedrag
Vanaf 3.0 staat EF Core alleen expressies toe in de projectie op het hoogste niveau (de laatste Select()
aanroep in de query) op de client te evalueren.
Wanneer expressies in een ander deel van de query niet kunnen worden geconverteerd naar SQL of een parameter, wordt er een uitzondering gegenereerd.
Waarom
Met automatische clientevaluatie van query's kunnen veel query's worden uitgevoerd, zelfs als belangrijke onderdelen ervan niet kunnen worden vertaald.
Dit gedrag kan leiden tot onverwacht en mogelijk schadelijk gedrag dat alleen in productie kan worden weergegeven.
Een voorwaarde in een Where()
-aanroep die niet kan worden vertaald, kan er bijvoorbeeld toe leiden dat alle rijen uit de tabel worden overgedragen van de databaseserver en dat het filter wordt toegepast op de client.
Deze situatie kan gemakkelijk onopgemerkt blijven als de tabel tijdens de ontwikkeling slechts een paar rijen heeft, maar zwaar weegt wanneer de toepassing naar productie gaat, waarbij de tabel mogelijk miljoenen rijen bevat.
Clientevaluatiewaarschuwingen zijn ook te gemakkelijk te negeren tijdens de ontwikkeling.
Daarnaast kan automatische clientevaluatie leiden tot problemen waarbij het verbeteren van queryomzetting voor specifieke expressies onbedoelde wijzigingen tussen releases veroorzaakte.
Maatregelen
Als een query niet volledig kan worden vertaald, herschrijft u de query in een formulier dat kan worden vertaald, of gebruikt u AsEnumerableAsync()
, ToListAsync()
of vergelijkbaar met het expliciet terugbrengen van gegevens naar de client, waar deze vervolgens verder kan worden verwerkt met LINQ-to-Objects.
Wijzigingen met gemiddelde impact
Entity Framework Core maakt geen deel meer uit van het gedeelde ASP.NET Core-framework
Aankondigingen van problemen bijhouden#325
Oud gedrag
Voordat ASP.NET Core 3.0, wanneer u een pakketverwijzing aan Microsoft.AspNetCore.App
of Microsoft.AspNetCore.All
hebt toegevoegd, zou dit EF Core en enkele EF Core-gegevensproviders zoals de SQL Server-provider bevatten.
Nieuw gedrag
Vanaf 3.0 bevat het gedeelde ASP.NET Core-framework geen EF Core- of EF Core-gegevensproviders.
Waarom
Voordat deze wijziging werd doorgevoerd, waren er verschillende stappen nodig om EF Core te verkrijgen, afhankelijk van of de toepassing gericht was op ASP.NET Core en SQL Server. Bovendien dwong het upgraden van ASP.NET Core de upgrade van EF Core en de SQL Server-provider af, wat niet altijd wenselijk is.
Met deze wijziging is de ervaring van het verkrijgen van EF Core hetzelfde voor alle providers, ondersteunde .NET-implementaties en toepassingstypen. Ontwikkelaars kunnen nu ook precies bepalen wanneer EF Core- en EF Core-gegevensproviders worden bijgewerkt.
Maatregelen
Als u EF Core wilt gebruiken in een ASP.NET Core 3.0-toepassing of een andere ondersteunde toepassing, voegt u expliciet een pakketverwijzing toe aan de EF Core-databaseprovider die door uw toepassing wordt gebruikt.
Het EF Core-opdrachtregelprogramma, dotnet ef, maakt niet langer deel uit van de .NET Core SDK
Oud gedrag
Vóór 3.0 was het hulpprogramma dotnet ef
opgenomen in de .NET Core SDK en was het direct beschikbaar voor gebruik vanaf de opdrachtregel vanuit een project zonder extra stappen.
Nieuw gedrag
Vanaf 3.0 bevat de .NET SDK het hulpprogramma dotnet ef
niet, dus voordat u het kunt gebruiken, moet u deze expliciet installeren als een lokaal of globaal hulpprogramma.
Waarom
Met deze wijziging kunnen we dotnet ef
distribueren en bijwerken als een gewoon .NET CLI-hulpprogramma op NuGet, consistent met het feit dat de EF Core 3.0 ook altijd wordt gedistribueerd als een NuGet-pakket.
Oplossingen
Als je migraties of een DbContext
wilt beheren, installeer dotnet-ef
als globaal hulpprogramma.
dotnet tool install --global dotnet-ef
U kunt het ook een lokaal hulpprogramma verkrijgen wanneer u de afhankelijkheden van een project herstelt die het declareert als een tooling-afhankelijkheid met behulp van een manifestbestand van een hulpprogramma.
Wijzigingen met lage impact
De naam van FromSql, ExecuteSql en ExecuteSqlAsync is gewijzigd
Belangrijk
ExecuteSqlCommand
en ExecuteSqlCommandAsync
zijn afgeschaft. Gebruik in plaats daarvan deze methoden.
Oud gedrag
Vóór EF Core 3.0 zijn deze methodenamen overbelast om te werken met een normale tekenreeks of een tekenreeks die moet worden geïnterpoleerd in SQL en parameters.
Nieuw gedrag
Gebruik vanaf EF Core 3.0 FromSqlRaw
, ExecuteSqlRaw
en ExecuteSqlRawAsync
om een geparameteriseerde query te maken waarbij de parameters afzonderlijk van de querytekenreeks worden doorgegeven.
Bijvoorbeeld:
context.Products.FromSqlRaw(
"SELECT * FROM Products WHERE Name = {0}",
product.Name);
Gebruik FromSqlInterpolated
, ExecuteSqlInterpolated
en ExecuteSqlInterpolatedAsync
om een geparameteriseerde query te maken waarin de parameters worden doorgegeven als onderdeel van een geïnterpoleerde querytekenreeks.
Bijvoorbeeld:
context.Products.FromSqlInterpolated(
$"SELECT * FROM Products WHERE Name = {product.Name}");
Houd er rekening mee dat beide bovenstaande query's dezelfde geparameteriseerde SQL met dezelfde SQL-parameters produceren.
Waarom
Methode-overbelastingen zoals deze maken het heel eenvoudig om per ongeluk de onbewerkte tekenreeksmethode aan te roepen wanneer de intentie was om de geïnterpoleerde tekenreeksmethode aan te roepen, en andersom. Dit kan ertoe leiden dat query's niet worden geparameteriseerd wanneer ze zouden moeten zijn.
Maatregelen
Schakel over naar de nieuwe methodenamen.
De FromSql-methode bij gebruik met opgeslagen procedure kan niet worden samengesteld
Oud gedrag
Vóór EF Core 3.0 probeerde de FromSql-methode te detecteren of de doorgegeven SQL kon worden samengesteld. Er werd clientevaluatie uitgevoerd toen de SQL niet-samenstelbaar was, zoals bij een opgeslagen procedure. De volgende query heeft gewerkt door de opgeslagen procedure uit te voeren op de server en FirstOrDefault aan de clientzijde uit te voeren.
context.Products.FromSqlRaw("[dbo].[Ten Most Expensive Products]").FirstOrDefault();
Nieuw gedrag
Vanaf EF Core 3.0 probeert EF Core de SQL niet te parseren. Dus als u na FromSqlRaw/FromSqlInterpolated opstelt, zal EF Core de SQL samenstellen door een subquery te genereren. Dus als u een opgeslagen procedure met samenstelling gebruikt, krijgt u een uitzondering voor ongeldige SQL-syntaxis.
Waarom
EF Core 3.0 biedt geen ondersteuning voor automatische clientevaluatie, omdat deze foutgevoelig was, zoals hier wordt uitgelegd hier.
Maatregelen
Als u een opgeslagen procedure gebruikt in FromSqlRaw/FromSqlInterpolated, weet u dat deze niet kan worden samengesteld, zodat u AsEnumerable
/AsAsyncEnumerable
direct na de aanroep van de FromSql-methode kunt toevoegen om elke samenstelling aan de serverzijde te voorkomen.
context.Products.FromSqlRaw("[dbo].[Ten Most Expensive Products]").AsEnumerable().FirstOrDefault();
FromSql-methoden kunnen alleen worden opgegeven in queryroots
Oud gedrag
Vóór EF Core 3.0 kan de methode FromSql
overal in de query worden opgegeven.
Nieuw gedrag
Vanaf EF Core 3.0 kunnen de nieuwe FromSqlRaw
- en FromSqlInterpolated
methoden (die FromSql
vervangen) alleen worden opgegeven op querywortels, dat wil bijvoorbeeld rechtstreeks op de DbSet<>
. Als u ze ergens anders probeert op te geven, treedt er een compilatiefout op.
Waarom
Het opgeven van FromSql
ergens anders dan op een DbSet
geen toegevoegde betekenis of toegevoegde waarde had, en kan in bepaalde scenario's dubbelzinnigheid veroorzaken.
Maatregelen
FromSql
aanroepen moeten rechtstreeks worden verplaatst naar de DbSet
waarop ze van toepassing zijn.
Geen traceringsquery's meer uitvoeren om identiteitsomzetting uit te voeren
Oud gedrag
Vóór EF Core 3.0 zou hetzelfde entiteitsexemplaar worden gebruikt voor elk exemplaar van een entiteit met een bepaald type en id. Dit komt overeen met het gedrag van het bijhouden van query's. Bijvoorbeeld deze query:
var results = await context.Products.Include(e => e.Category).AsNoTracking().ToListAsync();
retourneert dezelfde Category
instantie voor elke Product
die is gekoppeld aan de opgegeven categorie.
Nieuw gedrag
Vanaf EF Core 3.0 worden verschillende entiteitsexemplaren gemaakt wanneer een entiteit met een bepaald type en id op verschillende plaatsen in de geretourneerde grafiek wordt aangetroffen. De bovenstaande query retourneert bijvoorbeeld nu een nieuw Category
exemplaar voor elke Product
, zelfs wanneer twee producten aan dezelfde categorie zijn gekoppeld.
Waarom
Identiteitsomzetting (dat wil gezegd, bepalend dat een entiteit hetzelfde type en dezelfde id heeft als een eerder aangetroffen entiteit) voegt extra prestatie- en geheugenoverhead toe. Dit gaat meestal in tegen de reden waarom query's zonder tracering in de eerste plaats worden gebruikt. Hoewel identiteitsomzetting soms nuttig kan zijn, is het niet nodig als de entiteiten moeten worden geserialiseerd en verzonden naar een client, wat gebruikelijk is voor query's zonder tracering.
Maatregelen
Gebruik een traceringsquery indien identiteitsresolutie is vereist.
Tijdelijke sleutelwaarden worden niet meer ingesteld op entiteitsexemplaren
Oud gedrag
Vóór EF Core 3.0 werden tijdelijke waarden toegewezen aan alle sleuteleigenschappen die later een echte waarde zouden hebben die door de database werd gegenereerd. Meestal waren deze tijdelijke waarden grote negatieve getallen.
Nieuw gedrag
Vanaf 3.0 slaat EF Core de tijdelijke sleutelwaarde op als onderdeel van de traceringsgegevens van de entiteit en blijft de sleuteleigenschap zelf ongewijzigd.
Waarom
Deze wijziging is aangebracht om te voorkomen dat tijdelijke sleutelwaarden per ongeluk permanent worden wanneer een entiteit die eerder door een DbContext
exemplaar is bijgehouden, wordt verplaatst naar een ander DbContext
exemplaar.
Maatregelen
Toepassingen die primaire sleutelwaarden toewijzen aan refererende sleutels om koppelingen tussen entiteiten te vormen, zijn mogelijk afhankelijk van het oude gedrag als de primaire sleutels worden opgeslagen en behoren tot entiteiten met de status Added
.
Dit kan worden vermeden door:
- Niet het gebruik van door de winkel gegenereerde sleutels.
- Navigatie-eigenschappen instellen om relaties te vormen in plaats van het instellen van waarden voor buitenlandse sleutels.
- Haal de werkelijke tijdelijke sleutelwaarden op uit de traceringsgegevens van de entiteit.
context.Entry(blog).Property(e => e.Id).CurrentValue
retourneert bijvoorbeeld de tijdelijke waarde, ook al isblog.Id
zelf niet ingesteld.
DetectChanges erkent door de winkel gegenereerde sleutelwaarden
Oud gedrag
Vóór EF Core 3.0 wordt een niet-bijgehouden entiteit die door DetectChanges
is gevonden, bijgehouden in de status Added
en ingevoegd als een nieuwe rij wanneer SaveChanges
wordt aangeroepen.
Nieuw gedrag
Vanaf EF Core 3.0 wordt, als een entiteit gegenereerde sleutelwaarden gebruikt en er een sleutelwaarde is ingesteld, de entiteit in de status Modified
bijgehouden.
Dit betekent dat een rij voor de entiteit wordt verondersteld te bestaan en dat deze wordt bijgewerkt wanneer SaveChanges
wordt aangeroepen.
Als de sleutelwaarde niet is ingesteld of als het entiteitstype geen gegenereerde sleutels gebruikt, wordt de nieuwe entiteit nog steeds bijgehouden als Added
zoals in eerdere versies.
Waarom
Deze wijziging is aangebracht om het eenvoudiger en consistenter te maken om te werken met losgekoppelde entiteitsgrafieken tijdens het gebruik van door de store gegenereerde sleutels.
Maatregelen
Deze wijziging kan een toepassing breken als een entiteitstype is geconfigureerd voor het gebruik van gegenereerde sleutels, maar sleutelwaarden expliciet zijn ingesteld voor nieuwe exemplaren. De oplossing is om de sleuteleigenschappen expliciet te configureren om gegenereerde waarden niet te gebruiken. Bijvoorbeeld met de fluent-API:
modelBuilder
.Entity<Blog>()
.Property(e => e.Id)
.ValueGeneratedNever();
Of met gegevensaantekeningen:
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string Id { get; set; }
Trapsgewijs verwijderen gebeurt nu standaard onmiddellijk
Oud gedrag
Vóór 3.0 paste EF Core trapsgewijze acties toe (afhankelijke entiteiten verwijderen wanneer een vereiste principal wordt verwijderd of wanneer de relatie met een vereiste principal wordt verbroken), niet voordat SaveChanges werd aangeroepen.
Nieuw gedrag
Vanaf 3.0 past EF Core trapsgewijze acties toe zodra de triggervoorwaarde wordt gedetecteerd.
Als u bijvoorbeeld context.Remove()
aanroept om een principal-entiteit te verwijderen, worden alle bijgehouden vereiste afhankelijke afhankelijken ook onmiddellijk ingesteld op Deleted
.
Waarom
Deze wijziging is aangebracht om de ervaring voor gegevensbinding en controlescenario's te verbeteren, waarbij het belangrijk is te begrijpen welke entiteiten worden verwijderd voordatSaveChanges
wordt aangeroepen.
Maatregelen
Het vorige gedrag kan worden hersteld via instellingen op context.ChangeTracker
.
Bijvoorbeeld:
context.ChangeTracker.CascadeDeleteTiming = CascadeTiming.OnSaveChanges;
context.ChangeTracker.DeleteOrphansTiming = CascadeTiming.OnSaveChanges;
Het gretige laden van gerelateerde entiteiten vindt nu plaats in één query
probleem met bijhouden #18022
Oud gedrag
Voordat 3.0 verzamelingen-navigaties gretig werden geladen via Include
operators, werden er meerdere query's uitgevoerd op een relationele database, één voor elk gerelateerd entiteitstype.
Nieuw gedrag
Vanaf 3.0 genereert EF Core één query met JOI's voor relationele databases.
Waarom
Het uitgeven van meerdere query's voor het implementeren van één LINQ-query heeft talloze problemen veroorzaakt, waaronder negatieve prestaties als meerdere databaserondes nodig waren, en problemen met de coherentie van gegevens, omdat elke query een andere status van de database kon observeren.
Maatregelen
Hoewel dit technisch gezien geen belangrijke wijziging is, kan dit een aanzienlijk effect hebben op de prestaties van toepassingen wanneer één query een groot aantal Include
operator bevat voor verzamelingsnavigatie.
Zie deze opmerking voor meer informatie en voor het herschrijven van query's op een efficiëntere manier.
**
DeleteBehavior.Restrict heeft schonere semantiek
probleem met bijhouden #12661-
Oud gedrag
Vóór 3.0, maakte DeleteBehavior.Restrict
externe sleutels in de database met Restrict
- semantiek, maar veranderde ook de interne fixup op een onverwachte manier.
Nieuw gedrag
Vanaf 3.0 zorgt DeleteBehavior.Restrict
ervoor dat refererende sleutels worden aangemaakt met Restrict
semantiek, dat wil zeggen, geen cascades; uitwerpen bij schending van beperkingen, zonder invloed te hebben op interne EF-fixup.
Waarom
Deze wijziging is aangebracht om de ervaring voor het gebruik van DeleteBehavior
op een intuïtieve manier te verbeteren, zonder onverwachte bijwerkingen.
Oplossingen
Het vorige gedrag kan worden hersteld met behulp van DeleteBehavior.ClientNoAction
.
Querytypen worden samengevoegd met entiteitstypen
Oud gedrag
Vóór EF Core 3.0 waren querytypen een manier om query's uit te voeren op gegevens die geen primaire sleutel op een gestructureerde manier definiëren. Dat wil zeggen, werd er een querytype gebruikt voor het toewijzen van entiteitstypen zonder sleutels (waarschijnlijker vanuit een weergave, maar mogelijk uit een tabel), terwijl er een regulier entiteitstype werd gebruikt wanneer er een sleutel beschikbaar was (waarschijnlijker uit een tabel, maar mogelijk vanuit een weergave).
Nieuw gedrag
Een querytype wordt nu alleen een entiteitstype zonder primaire sleutel. Sleutelloze entiteitstypen hebben dezelfde functionaliteit als querytypen in eerdere versies.
Waarom
Deze wijziging is aangebracht om de verwarring rond het doel van querytypen te verminderen. Ze zijn met name sleutelloze entiteitstypen en ze zijn inherent alleen-lezen vanwege dit, maar ze mogen niet alleen worden gebruikt omdat een entiteitstype alleen-lezen moet zijn. Op dezelfde manier worden ze vaak toegewezen aan weergaven, maar dit komt alleen omdat weergaven vaak geen sleutels definiëren.
Oplossingen
De volgende onderdelen van de API zijn nu verouderd:
-
ModelBuilder.Query<>()
: in plaats daarvan moetModelBuilder.Entity<>().HasNoKey()
worden aangeroepen om een entiteitstype te markeren als geen sleutels. Dit zou nog steeds niet volgens de conventie worden geconfigureerd om onjuiste configuratie te voorkomen wanneer een primaire sleutel wordt verwacht, maar niet overeenkomt met de conventie. -
DbQuery<>
: in plaats daarvan moetDbSet<>
worden gebruikt. -
DbContext.Query<>()
: in plaats daarvan moetDbContext.Set<>()
worden gebruikt. -
IQueryTypeConfiguration<TQuery>
: in plaats daarvan moetIEntityTypeConfiguration<TEntity>
worden gebruikt.
Notitie
Vanwege een probleem in 3.x bij het uitvoeren van query's op sleutelloze entiteiten waarop alle eigenschappen zijn ingesteld op null
wordt een null
geretourneerd in plaats van een entiteit, als dit probleem ook van toepassing is op uw scenario, voegt u logica toe om null
in resultaten te verwerken.
nl-NL: Configuratie-API voor relaties van 'owned types' is gewijzigd
Probleem bijhouden #12444TrackingProbleem #9148TrackingProbleem #14153
Oud gedrag
Vóór EF Core 3.0 werd de configuratie van de eigendomrelatie onmiddellijk na de OwnsOne
- of OwnsMany
-aanroep uitgevoerd.
Nieuw gedrag
Vanaf EF Core 3.0 is er een fluent API beschikbaar om een navigatie-eigenschap naar de eigenaar te configureren met behulp van WithOwner()
.
Bijvoorbeeld:
modelBuilder.Entity<Order>.OwnsOne(e => e.Details).WithOwner(e => e.Order);
De configuratie met betrekking tot de relatie tussen eigenaar en eigendom moet nu worden gekoppeld na WithOwner()
vergelijkbaar met de configuratie van andere relaties.
Hoewel de configuratie voor het eigendomstype zelf nog steeds gekoppeld wordt na OwnsOne()/OwnsMany()
.
Bijvoorbeeld:
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
});
});
Als u Entity()
, HasOne()
of Set()
aanroept met een doelobject van het type eigendom, wordt er voortaan een uitzondering gegenereerd.
Waarom
Deze wijziging is aangebracht om een helderder scheiding te maken tussen het configureren van het type zelf en de relatie tot het eigendomstype.
Dit verwijdert op zijn beurt dubbelzinnigheid en verwarring rond methoden zoals HasForeignKey
.
Maatregelen
Wijzig de configuratie van eigendomsrelaties om de nieuwe API-interface te gebruiken, zoals wordt weergegeven in het bovenstaande voorbeeld.
Afhankelijke entiteiten die de tabel delen met de principal zijn nu optioneel
Oud gedrag
Houd rekening met het volgende model:
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; }
}
Vóór EF Core 3.0, als OrderDetails
eigendom is van Order
of expliciet is toegewezen aan dezelfde tabel, was er altijd een OrderDetails
exemplaar vereist bij het toevoegen van een nieuwe Order
.
Nieuw gedrag
Vanaf 3.0 staat EF Core toe een Order
zonder een OrderDetails
toe te voegen en kent alle OrderDetails
eigenschappen, behalve de primaire sleutel, toe aan null-kolommen.
Bij het uitvoeren van een query op EF Core wordt OrderDetails
ingesteld op null
als een van de vereiste eigenschappen geen waarde heeft of als er geen vereiste eigenschappen naast de primaire sleutel zijn en alle eigenschappen zijn null
.
Oplossingen
Als uw model een tabelafhankelijke relatie heeft met alle kolommen als optioneel, maar de navigatie die ernaar wijst niet null
hoeft te zijn, moet de toepassing worden aangepast om gevallen af te handelen wanneer de navigatie null
is. Als dit niet mogelijk is, moet een vereiste eigenschap worden toegevoegd aan het entiteitstype of moet ten minste één eigenschap een niet-null
waarde hebben die eraan is toegewezen.
Alle entiteiten die een tabel met een gelijktijdigheidstokenkolom delen, moeten deze toewijzen aan een eigenschap
Oud gedrag
Houd rekening met het volgende model:
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");
}
Voor EF Core 3.0, als OrderDetails
eigendom is van Order
of expliciet aan dezelfde tabel is toegewezen, zal het bijwerken van alleen OrderDetails
de Version
-waarde op de client niet bijwerken, en zal de volgende update mislukken.
Nieuw gedrag
Vanaf 3.0 wordt de nieuwe Version
waarde door EF Core doorgegeven aan Order
als deze eigenaar is van OrderDetails
. Anders wordt er een uitzondering gegenereerd tijdens modelvalidatie.
Waarom
Deze wijziging is aangebracht om een verouderde gelijktijdigheidstokenwaarde te voorkomen wanneer slechts één van de entiteiten die aan dezelfde tabel zijn toegewezen, wordt bijgewerkt.
Risicobeperkingen
Alle entiteiten die de tabel delen, moeten een eigenschap opnemen die is toegewezen aan de kolom met gelijktijdigheidstokens. Het is mogelijk dat u er een maakt met de schaduwstatus:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<OrderDetails>()
.Property<byte[]>("Version").IsRowVersion().HasColumnName("Version");
}
Entiteiten in eigendom kunnen niet worden opgevraagd zonder de eigenaar met behulp van een traceringsquery
Oud gedrag
Vóór EF Core 3.0 konden gebonden entiteiten worden opgevraagd als elke andere navigatie.
context.People.Select(p => p.Address);
Nieuw gedrag
Vanaf 3.0 genereert EF Core een traceringsquery die een entiteit in eigendom zonder de eigenaar projecteert.
Waarom
Entiteiten in eigendom kunnen niet worden gemanipuleerd zonder de eigenaar, dus in het overgrote deel van de gevallen waarin ze op deze manier worden opgevraagd, is dit een fout.
Maatregelen
Als de entiteit in eigendom moet worden bijgehouden om later te worden gewijzigd, moet de eigenaar worden opgenomen in de query.
Voeg anders een AsNoTracking()
-aanroep toe:
context.People.Select(p => p.Address).AsNoTracking();
Overgenomen eigenschappen van niet-toegewezen typen worden nu toegewezen aan één kolom voor alle afgeleide typen
Oud gedrag
Houd rekening met het volgende model:
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>();
}
Vóór EF Core 3.0 wordt de eigenschap ShippingAddress
standaard toegewezen aan afzonderlijke kolommen voor BulkOrder
en Order
.
Nieuw gedrag
Vanaf 3.0 maakt EF Core slechts één kolom voor ShippingAddress
.
Waarom
Het oude gedrag was onverwacht.
Maatregelen
De eigenschap kan nog steeds expliciet worden toegewezen aan afzonderlijke kolommen van de afgeleide typen:
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");
}
De conventie van de vreemde-sleuteleigenschap komt niet meer overeen met de naam van de hoofdeigenschap.
Oud gedrag
Houd rekening met het volgende model:
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; }
}
Vóór EF Core 3.0 werd de eigenschap CustomerId
per conventie gebruikt voor de vreemde sleutel.
Als Order
echter een eigendomstype is, zou dit ook betekenen dat CustomerId
de primaire sleutel wordt, en dat is meestal niet wat verwacht wordt.
Nieuw gedrag
Vanaf 3.0 probeert EF Core standaard geen eigenschappen te gebruiken voor foreign keys als deze dezelfde naam hebben als de principal-eigenschap. De naam van het principal-type, samengevoegd met de naam van de principal-eigenschap, en de navigatienaam, samengevoegd met de patronen van principal-eigenschapsnamen, komen nog steeds overeen. Bijvoorbeeld:
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; }
}
Waarom
Deze wijziging is aangebracht om te voorkomen dat er per ongeluk een primaire sleuteleigenschap wordt gedefinieerd voor het type eigendom.
Oplossingen
Als de eigenschap bedoeld was om de vreemde sleutel te zijn en dus onderdeel van de primaire sleutel, configureert u deze expliciet als zodanig.
Databaseverbinding is nu gesloten als deze niet meer wordt gebruikt voordat de TransactionScope is voltooid
Oud gedrag
Voordat EF Core 3.0, als de context de verbinding binnen een TransactionScope
opent, blijft de verbinding geopend terwijl de huidige TransactionScope
actief is.
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();
}
}
Nieuw gedrag
Vanaf versie 3.0 sluit EF Core de verbinding zodra het klaar is met het gebruik ervan.
Waarom
Met deze wijziging kunt u meerdere contexten in dezelfde TransactionScope
gebruiken. Het nieuwe gedrag komt ook overeen met EF6.
Maatregelen
Als de verbinding open moet blijven staan expliciete aanroep naar OpenConnection()
zorgt ervoor dat EF Core deze niet voortijdig sluit:
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();
}
}
Elke eigenschap maakt gebruik van onafhankelijke in-memory generatie van integersleutels
Oud gedrag
Vóór EF Core 3.0 werd één gedeelde waarde-generator gebruikt voor alle geheugensleuteleigenschappen met gehele getallen.
Nieuw gedrag
Vanaf EF Core 3.0 krijgt elke eigenschap voor gehele getallen een eigen waardegenerator wanneer de database in het geheugen wordt gebruikt. Als de database wordt verwijderd, wordt het genereren van sleutels voor alle tabellen opnieuw ingesteld.
Waarom
Deze wijziging is aangebracht om het genereren van sleutels in het geheugen nauwkeuriger af te stemmen op het genereren van echte databasesleutels en om de mogelijkheid om tests van elkaar te isoleren bij gebruik van de in-memory database te verbeteren.
Maatregelen
Dit kan een toepassing verbreken die afhankelijk is van specifieke waarden in het geheugen die moeten worden ingesteld. Overweeg in plaats daarvan niet te vertrouwen op specifieke sleutelwaarden of om bij te werken om overeen te komen met het nieuwe gedrag.
Ondersteunende velden worden standaard toegepast
Oud gedrag
Vóór 3.0, zelfs als het achterliggende veld voor een eigenschap bekend was, las en schreef EF Core de eigenschapswaarde nog steeds standaard met behulp van de getter- en settermethoden van de eigenschap. De uitzondering hierop was het uitvoeren van query's, waarbij het back-upveld direct zou worden ingesteld als dit bekend is.
Nieuw gedrag
Beginnend met EF Core 3.0, als het backingveld voor een eigenschap bekend is, zal EF Core die eigenschap altijd lezen en schrijven met behulp van het backingveld. Dit kan een toepassingsonderbreking veroorzaken als de toepassing afhankelijk is van aanvullend gedrag dat is gecodeerd in de getter- of settermethoden.
Waarom
Deze wijziging is aangebracht om te voorkomen dat EF Core per ongeluk bedrijfslogica activeert bij het uitvoeren van databasebewerkingen met betrekking tot de entiteiten.
Maatregelen
Het gedrag vóór 3.0 kan worden hersteld via de configuratie van de eigenschapstoegangsmodus op ModelBuilder
.
Bijvoorbeeld:
modelBuilder.UsePropertyAccessMode(PropertyAccessMode.PreferFieldDuringConstruction);
Gooien als er meerdere compatibele backingvelden worden gevonden
Oud gedrag
Vóór EF Core 3.0, als meerdere velden overeenkomen met de regels voor het vinden van het backingveld van een eigenschap, wordt één veld gekozen op basis van een bepaalde prioriteitsvolgorde. Dit kan ertoe leiden dat het verkeerde veld wordt gebruikt in dubbelzinnige gevallen.
Nieuw gedrag
Vanaf EF Core 3.0 wordt er een uitzondering gegenereerd als meerdere velden overeenkomen met dezelfde eigenschap.
Waarom
Deze wijziging is aangebracht om te voorkomen dat het ene veld stilletjes boven een ander veld wordt verkozen wanneer slechts één veld correct kan zijn.
Oplossingen
Eigenschappen met onduidelijke achterliggende velden moeten expliciet het te gebruiken veld opgegeven krijgen. Gebruik bijvoorbeeld de fluent-API:
modelBuilder
.Entity<Blog>()
.Property(e => e.Id)
.HasField("_id");
Eigenschapsnamen die alleen voor velden gelden, moeten overeenkomen met de veldnaam.
Oud gedrag
Vóór EF Core 3.0 kan een eigenschap worden opgegeven met een tekenreekswaarde en als er geen eigenschap met die naam is gevonden op het .NET-type, probeert EF Core deze te koppelen aan een veld met behulp van conventieregels.
private class Blog
{
private int _id;
public string Name { get; set; }
}
modelBuilder
.Entity<Blog>()
.Property("Id");
Nieuw gedrag
Vanaf EF Core 3.0 moet een veldeigenschap exact overeenkomen met de veldnaam.
modelBuilder
.Entity<Blog>()
.Property("_id");
Waarom
Deze wijziging is aangebracht om te voorkomen dat hetzelfde veld wordt gebruikt voor twee eigenschappen die op dezelfde manier worden genoemd. Ook worden de overeenkomende regels voor alleen-veldeigenschappen hetzelfde als voor eigenschappen die zijn toegewezen aan CLR-eigenschappen.
Oplossingen
Veldeigen eigenschappen moeten dezelfde naam hebben als het veld waaraan ze zijn toegewezen. In een toekomstige release van EF Core na 3.0 zijn we van plan om expliciet een veldnaam te configureren die verschilt van de eigenschapsnaam (zie probleem #15307):
modelBuilder
.Entity<Blog>()
.Property("Id")
.HasField("_id");
AddDbContext/AddDbContextPool roept AddLogging en AddMemoryCache niet meer aan
Oud gedrag
Vóór EF Core 3.0 registreert het aanroepen van AddDbContext
of AddDbContextPool
ook services voor logboekregistratie en geheugencaching bij DI via aanroepen naar AddLogging- en AddMemoryCache-.
Nieuw gedrag
Vanaf EF Core 3.0 registreren AddDbContext
en AddDbContextPool
deze services niet meer bij Dependency Injection (DI).
Waarom
EF Core 3.0 vereist niet dat deze services zich in de DI-container van de toepassing bevinden. Als ILoggerFactory
echter is geregistreerd in de DI-container van de toepassing, wordt deze nog steeds gebruikt door EF Core.
Maatregelen
Als uw toepassing deze services nodig heeft, registreert u deze expliciet bij de DI-container met behulp van AddLogging- of AddMemoryCache-.
AddEntityFramework* voegt IMemoryCache toe met een groottelimiet
Oud gedrag
Voor EF Core 3.0 zou het aanroepen van AddEntityFramework*
-methoden ook geheugencachingservices bij DI registreren zonder een groottelimiet.
Nieuw gedrag
Vanaf EF Core 3.0 registreert AddEntityFramework*
een IMemoryCache-service met een groottelimiet. Als andere services die later worden toegevoegd, afhankelijk zijn van IMemoryCache, kunnen ze snel de standaardlimiet bereiken die uitzonderingen of verminderde prestaties veroorzaken.
Waarom
Het gebruik van IMemoryCache zonder limiet kan leiden tot onbeheerd geheugengebruik als er een fout optreedt in de cachelogica van query's of als de query's dynamisch worden gegenereerd. Als u een standaardlimiet hebt, wordt een mogelijke DoS-aanval beperkt.
Oplossingen
In de meeste gevallen is het aanroepen van AddEntityFramework*
niet nodig als AddDbContext
of AddDbContextPool
ook wordt aangeroepen. Daarom is de beste oplossing om de AddEntityFramework*
aanroep te verwijderen.
Als uw toepassing deze services nodig heeft, moet u vooraf een IMemoryCache-implementatie registreren bij de DI-container met behulp van AddMemoryCache.
DbContext.Entry voert nu een lokale DetectChanges uit
Oud gedrag
Voor EF Core 3.0 zou het aanroepen van DbContext.Entry
ervoor zorgen dat wijzigingen voor alle bijgehouden entiteiten werden gedetecteerd.
Dit zorgde ervoor dat de toestand die in de EntityEntry
werd weergegeven, overeenkwam met de up-to-datum.
Nieuw gedrag
Vanaf EF Core 3.0 probeert het aanroepen van DbContext.Entry
nu alleen wijzigingen in de opgegeven entiteit en eventuele bijgehouden principal-entiteiten die hieraan zijn gerelateerd, te detecteren.
Dit betekent dat wijzigingen elders mogelijk niet zijn gedetecteerd door deze methode aan te roepen, wat gevolgen kan hebben voor de toepassingsstatus.
Houd er rekening mee dat als ChangeTracker.AutoDetectChangesEnabled
is ingesteld op false
, zelfs deze lokale wijzigingsdetectie wordt uitgeschakeld.
Andere methoden die wijzigingsdetectie veroorzaken, bijvoorbeeld ChangeTracker.Entries
en SaveChanges
, veroorzaken nog steeds een volledige DetectChanges
van alle bijgehouden entiteiten.
Waarom
Deze wijziging is aangebracht om de standaardprestaties van het gebruik van context.Entry
te verbeteren.
Beperkingen
Roep ChangeTracker.DetectChanges()
expliciet aan voordat u Entry
belt om ervoor te zorgen dat het gedrag van vóór 3.0 wordt gegarandeerd.
Tekenreeks- en bytematrixsleutels worden niet standaard door de client gegenereerd
Oud gedrag
Vóór EF Core 3.0 kunnen string
en byte[]
sleuteleigenschappen worden gebruikt zonder expliciet een niet-null-waarde in te stellen.
In dat geval wordt de sleutelwaarde op de client gegenereerd als een GUID, geserialiseerd tot bytes voor byte[]
.
Nieuw gedrag
Vanaf EF Core 3.0 wordt een uitzondering gegenereerd die aangeeft dat er geen sleutelwaarde is ingesteld.
Waarom
Deze wijziging is aangebracht omdat door de client gegenereerde string
/byte[]
waarden doorgaans niet nuttig zijn en het standaardgedrag maakte het moeilijk om op een gemeenschappelijke manier redeneren over gegenereerde sleutelwaarden.
Maatregelen
Het gedrag vóór 3.0 kan worden verkregen door expliciet op te geven dat de sleuteleigenschappen gegenereerde waarden moeten gebruiken als er geen andere niet-null-waarde is ingesteld. Bijvoorbeeld met de fluent-API:
modelBuilder
.Entity<Blog>()
.Property(e => e.Id)
.ValueGeneratedOnAdd();
Of met gegevensaantekeningen:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }
ILoggerFactory is nu een 'scoped service' (een in omvang beperkte dienst)
Oud gedrag
Voor EF Core 3.0 werd ILoggerFactory
als singletonservice geregistreerd.
Nieuw gedrag
Vanaf EF Core 3.0 wordt ILoggerFactory
nu geregistreerd als gescopeerd.
Waarom
Deze wijziging is aangebracht om de koppeling van een logger met een DbContext
exemplaar mogelijk te maken, waardoor andere functionaliteit mogelijk is en sommige gevallen van pathologisch gedrag, zoals een explosie van interne serviceproviders, worden verwijderd.
Mitigerende maatregelen
Deze wijziging mag geen invloed hebben op toepassingscode, tenzij deze aangepaste services registreert en gebruikt op de interne EF Core-serviceprovider.
Dit is niet gebruikelijk.
In deze gevallen werken de meeste dingen nog steeds, maar elke singleton-service die afhankelijk is van ILoggerFactory
moet worden gewijzigd om de ILoggerFactory
op een andere manier te verkrijgen.
Als u dergelijke situaties ondervindt, dient u een probleem in op de EF Core GitHub GitHub-probleemtracker om ons te laten weten hoe u ILoggerFactory
gebruikt, zodat we beter begrijpen hoe we dit in de toekomst niet opnieuw kunnen verbreken.
Luie laadproxies gaan er niet langer van uit dat navigatie-eigenschappen volledig zijn geladen
Oud gedrag
Vóór EF Core 3.0 was er, zodra een DbContext
was disposeerd, geen manier om te weten of een bepaalde navigatie-eigenschap op een entiteit verkregen uit die context volledig was geladen of niet.
Proxy's gaan er in plaats daarvan van uit dat een verwijzingsnavigatie wordt geladen als deze een niet-null-waarde heeft en dat een verzamelingsnavigatie wordt geladen als deze niet leeg is.
In dergelijke gevallen zou een poging om te lazy-loaden een no-opzijn.
Nieuw gedrag
Vanaf EF Core 3.0 houden proxy's bij of er al dan niet een navigatie-eigenschap wordt geladen. Dit betekent dat een poging om toegang te krijgen tot een navigatie-eigenschap die wordt geladen nadat de context is verwijderd, altijd een no-opis, zelfs wanneer de geladen navigatie leeg of null is. Als u echter probeert toegang te krijgen tot een navigatie-eigenschap die niet is geladen, wordt er een uitzondering gegenereerd als de context wordt verwijderd, zelfs als de navigatie-eigenschap een niet-lege verzameling is. Als deze situatie zich voordoet, betekent dit dat de toepassingscode probeert lazyloading op een ongeldig tijdstip te gebruiken en dat de toepassing moet worden gewijzigd om dit niet te doen.
Waarom
Deze wijziging is aangebracht om het gedrag consistent en correct te maken bij het lazy-loaden van een opgeheven DbContext
-exemplaar.
Maatregelen
Werk de toepassingscode bij om niet te proberen lazy-loading te gebruiken met een afgesloten context, of configureer dit als een no-op zoals beschreven in de foutmelding.
Overmatige creatie van interne serviceproviders is nu standaard een fout
Oud gedrag
Vóór EF Core 3.0, werd een waarschuwing vastgelegd voor een toepassing die een pathologisch aantal interne service-providers creëerde.
Nieuw gedrag
Vanaf EF Core 3.0 wordt deze waarschuwing nu beschouwd als een fout en treedt er een uitzondering op.
Waarom
Deze wijziging is aangebracht om betere toepassingscode te stimuleren door deze pathologische case expliciet zichtbaar te maken.
Maatregelen
De meest geschikte handelswijze bij het optreden van deze fout is het begrijpen van de hoofdoorzaak en stoppen met het creëren van zoveel interne serviceproviders.
De fout kan echter opnieuw worden geconverteerd naar een waarschuwing (of genegeerd) via de configuratie op de DbContextOptionsBuilder
.
Bijvoorbeeld:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.ConfigureWarnings(w => w.Log(CoreEventId.ManyServiceProvidersCreatedWarning));
}
Nieuw gedrag voor HasOne/HasMany aangeroepen met één tekenreeks
Oud gedrag
Vóór EF Core 3.0 werd code die HasOne
of HasMany
aanroept met één tekenreeks op een verwarrende manier geïnterpreteerd.
Bijvoorbeeld:
modelBuilder.Entity<Samurai>().HasOne("Entrance").WithOne();
De code lijkt verband te houden tussen Samurai
en een ander entiteitstype met behulp van de mogelijk privé Entrance
-navigatie-eigenschap.
In werkelijkheid probeert deze code een relatie te maken met een bepaald entiteitstype met de naam Entrance
zonder navigatie-eigenschap.
Nieuw gedrag
Vanaf EF Core 3.0 werkt de bovenstaande code nu zoals het eerder had moeten doen.
Waarom
Het oude gedrag was erg verwarrend, vooral bij het lezen van de configuratiecode en het zoeken naar fouten.
Maatregelen
Hierdoor worden alleen toepassingen verbroken die expliciet relaties configureren met behulp van tekenreeksen voor typenamen en zonder expliciet de navigatie-eigenschap op te geven.
Dit is niet gebruikelijk.
Het vorige gedrag kan worden verkregen door null
expliciet als de naam van de navigatie-eigenschap door te geven.
Bijvoorbeeld:
modelBuilder.Entity<Samurai>().HasOne("Some.Entity.Type.Name", null).WithOne();
Het retourtype voor verschillende asynchrone methoden is gewijzigd van Taak in ValueTask
Oud gedrag
De volgende asynchrone methoden hebben eerder een Task<T>
geretourneerd:
DbContext.FindAsync()
DbSet.FindAsync()
DbContext.AddAsync()
DbSet.AddAsync()
-
ValueGenerator.NextValueAsync()
(en afgeleide klassen)
Nieuw gedrag
De bovengenoemde methoden retourneren nu een ValueTask<T>
over dezelfde T
als voorheen.
Waarom
Deze wijziging vermindert het aantal heap-toewijzingen dat wordt gemaakt bij het aanroepen van deze methoden, waardoor de algemene prestaties worden verbeterd.
Maatregelen
Toepassingen die alleen wachten op de bovenstaande API's hoeven alleen opnieuw te worden gecompileerd. Er zijn geen bronwijzigingen nodig.
Een complexer gebruik (bijvoorbeeld het doorgeven van de geretourneerde Task
aan Task.WhenAny()
) vereist doorgaans dat de geretourneerde ValueTask<T>
worden geconverteerd naar een Task<T>
door er AsTask()
op aan te roepen.
Houd er rekening mee dat hiermee de toewijzingsvermindering wordt weggenomen die deze wijziging brengt.
De annotatie Relational:TypeMapping is nu gewoon TypeMapping
Oud gedrag
De annotatienaam voor typetoewijzingsannotaties was 'Relational:TypeMapping'.
Nieuw gedrag
De naam van de aantekening voor typetoewijzingsaantekeningen is nu 'TypeMapping'.
Waarom
Typetoewijzingen worden nu gebruikt voor meer dan alleen relationele databaseproviders.
Beperkingsmaatregelen
Hierdoor worden alleen toepassingen onderbroken die direct toegang hebben tot de typekoppeling in de vorm van een aantekening, wat niet gebruikelijk is. De meest geschikte actie om te corrigeren, is om de API-interface te gebruiken voor toegang tot typemappingen in plaats van de annotatie rechtstreeks te gebruiken.
ToTable op een afgeleid type genereert een uitzondering
Oud gedrag
Vóór EF Core 3.0 zou een aanroep van ToTable()
op een afgeleid type worden genegeerd, omdat de enige overnametoewijzingsstrategie TPH was, en dit daarin niet geldig is.
Nieuw gedrag
Vanaf EF Core 3.0, en ter voorbereiding op het toevoegen van ondersteuning voor TPT en TPC in een latere release, zal een aanroep van ToTable()
op een afgeleid type nu een uitzondering genereren om onverwachte toewijzingswijzigingen in de toekomst te voorkomen.
Waarom
Momenteel is het niet geldig om een afgeleid type toe te wijzen aan een andere tabel. Deze wijziging voorkomt dat er in de toekomst fouten optreden wanneer het een geldige taak wordt.
Maatregelen
Verwijder alle pogingen om afgeleide typen toe te wijzen aan andere tabellen.
ForSqlServerHasIndex vervangen door HasIndex
Oud gedrag
Voor EF Core 3.0 bood ForSqlServerHasIndex().ForSqlServerInclude()
een manier om kolommen te configureren die werden gebruikt met INCLUDE
.
Nieuw gedrag
Vanaf EF Core 3.0 wordt het gebruik van Include
op een index nu ondersteund op relationeel niveau.
Gebruik HasIndex().ForSqlServerInclude()
.
Waarom
Deze wijziging is aangebracht om de API voor indexen samen te voegen met Include
op één plaats voor alle databaseproviders.
Maatregelen
Gebruik de nieuwe API, zoals hierboven wordt weergegeven.
Wijzigingen in metagegevens-API
Nieuw gedrag
De volgende eigenschappen zijn geconverteerd naar extensiemethoden:
-
IEntityType.QueryFilter
->GetQueryFilter()
-
IEntityType.DefiningQuery
->GetDefiningQuery()
-
IProperty.IsShadowProperty
->IsShadowProperty()
-
IProperty.BeforeSaveBehavior
->GetBeforeSaveBehavior()
-
IProperty.AfterSaveBehavior
->GetAfterSaveBehavior()
Waarom
Deze wijziging vereenvoudigt de implementatie van bovengenoemde interfaces.
Maatregelen
Gebruik de nieuwe extensiemethoden.
Wijzigingen in de API voor providerspecifieke metagegevens
Nieuw gedrag
De providerspecifieke uitbreidingsmethoden worden afgevlakt:
-
IProperty.Relational().ColumnName
->IProperty.GetColumnName()
-
IEntityType.SqlServer().IsMemoryOptimized
->IEntityType.IsMemoryOptimized()
-
PropertyBuilder.UseSqlServerIdentityColumn()
->PropertyBuilder.UseIdentityColumn()
Waarom
Deze wijziging vereenvoudigt de implementatie van de bovengenoemde uitbreidingsmethoden.
Maatregelen
Gebruik de nieuwe extensiemethoden.
EF Core verzendt geen pragma meer voor SQLite FK-afdwinging
Oud gedrag
Vóór EF Core 3.0 zou EF Core PRAGMA foreign_keys = 1
verzenden wanneer een verbinding met SQLite wordt geopend.
Nieuw gedrag
Vanaf EF Core 3.0 verzendt EF Core geen PRAGMA foreign_keys = 1
meer wanneer een verbinding met SQLite wordt geopend.
Waarom
Deze wijziging is aangebracht omdat EF Core standaard gebruikmaakt van SQLitePCLRaw.bundle_e_sqlite3
, wat op zijn beurt betekent dat FK-afdwinging standaard is ingeschakeld en niet expliciet hoeft te worden ingeschakeld telkens wanneer een verbinding wordt geopend.
Maatregelen
Vreemde sleutels worden standaard ingeschakeld in SQLitePCLRaw.bundle_e_sqlite3, dat standaard wordt gebruikt voor EF Core.
In andere gevallen kunnen vreemde sleutels worden ingeschakeld door Foreign Keys=True
op te geven in uw verbindingsreeks.
Microsoft.EntityFrameworkCore.Sqlite is nu afhankelijk van SQLitePCLRaw.bundle_e_sqlite3
Oud gedrag
Vóór EF Core 3.0 gebruikte EF Core SQLitePCLRaw.bundle_green
.
Nieuw gedrag
Vanaf EF Core 3.0 maakt EF Core gebruik van SQLitePCLRaw.bundle_e_sqlite3
.
Waarom
Deze wijziging is aangebracht zodat de versie van SQLite die wordt gebruikt op iOS consistent is met andere platforms.
Oplossingen
Als u de systeemeigen SQLite-versie in iOS wilt gebruiken, configureert u Microsoft.Data.Sqlite
om een andere SQLitePCLRaw
bundel te gebruiken.
Guid-waarden worden nu opgeslagen als TEKST op SQLite
Oud gedrag
Guid-waarden werden eerder opgeslagen als BLOB-waarden op SQLite.
Nieuw gedrag
Guid-waarden worden nu opgeslagen als TEKST.
Waarom
De binaire indeling van Guids is niet gestandaardiseerd. Door de waarden op te slaan als TEKST, is de database beter compatibel met andere technologieën.
Oplossingen
U kunt bestaande databases migreren naar de nieuwe indeling door SQL als volgt uit te voeren.
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';
In EF Core kunt u ook het vorige gedrag blijven gebruiken door een waardeconversieprogramma voor deze eigenschappen te configureren.
modelBuilder
.Entity<MyEntity>()
.Property(e => e.GuidProperty)
.HasConversion(
g => g.ToByteArray(),
b => new Guid(b));
Microsoft.Data.Sqlite kan guid-waarden lezen uit zowel BLOB- als TEKSTkolommen; Aangezien de standaardindeling voor parameters en constanten echter is gewijzigd, moet u waarschijnlijk actie ondernemen voor de meeste scenario's met Guids.
Tekenwaarden worden nu opgeslagen als TEKST op SQLite
Oud gedrag
Tekenwaarden werden eerder opgeslagen als INTEGER-waarden op SQLite. Een tekenwaarde van A- is bijvoorbeeld opgeslagen als de gehele waarde 65.
Nieuw gedrag
Tekenwaarden worden nu opgeslagen als tekst.
Waarom
Het opslaan van de waarden als TEKST is natuurlijker en maakt de database compatibeler met andere technologieën.
Maatregelen
U kunt bestaande databases migreren naar de nieuwe indeling door SQL als volgt uit te voeren.
UPDATE MyTable
SET CharColumn = char(CharColumn)
WHERE typeof(CharColumn) = 'integer';
In EF Core kunt u ook het vorige gedrag blijven gebruiken door een waardeconversieprogramma voor deze eigenschappen te configureren.
modelBuilder
.Entity<MyEntity>()
.Property(e => e.CharProperty)
.HasConversion(
c => (long)c,
i => (char)i);
Microsoft.Data.Sqlite kan ook tekenwaarden lezen uit kolommen GEHEEL GETAL en TEKST, dus voor bepaalde scenario's is mogelijk geen actie vereist.
Migratie-id's worden nu gegenereerd met behulp van de agenda van de invariante cultuur
Oud gedrag
Migratie-id's zijn per ongeluk gegenereerd met behulp van de agenda van de huidige cultuur.
Nieuw gedrag
Migratie-id's worden nu altijd gegenereerd met behulp van de kalender van de invariante cultuur (Gregoriaanse).
Waarom
De volgorde van migraties is belangrijk bij het bijwerken van de database of het oplossen van samenvoegingsconflicten. Het gebruik van de invariante agenda voorkomt ordeproblemen die kunnen voortvloeien uit teamleden die verschillende systeemkalenders hebben.
Mitigerende maatregelen
Deze wijziging is van invloed op iedereen die een niet-Gregoriaanse kalender gebruikt waar het jaar groter is dan de Gregoriaanse kalender (zoals de Thaise boeddhistische kalender). Bestaande migratie-id's moeten worden bijgewerkt, zodat nieuwe migraties na bestaande migraties worden geordend.
De migratie-id vindt u in het kenmerk Migratie in de ontwerpbestanden van de migraties.
[DbContext(typeof(MyDbContext))]
-[Migration("25620318122820_MyMigration")]
+[Migration("20190318122820_MyMigration")]
partial class MyMigration
{
De geschiedenistabel migraties moet ook worden bijgewerkt.
UPDATE __EFMigrationsHistory
SET MigrationId = CONCAT(LEFT(MigrationId, 4) - 543, SUBSTRING(MigrationId, 4, 150))
UseRowNumberForPaging werd verwijderd
Oud gedrag
Vóór EF Core 3.0 kan UseRowNumberForPaging
worden gebruikt om SQL te genereren voor paging die compatibel is met SQL Server 2008.
Nieuw gedrag
Vanaf EF Core 3.0 genereert EF alleen SQL voor paging die alleen compatibel is met latere SQL Server-versies.
Waarom
Deze wijziging wordt aangebracht omdat SQL Server 2008 geen ondersteund product meer is en het significant werk is om deze functie bij te werken zodat deze werkt met de querywijzigingen die in EF Core 3.0 zijn doorgevoerd.
Maatregelen
U wordt aangeraden bij te werken naar een nieuwere versie van SQL Server of een hoger compatibiliteitsniveau te gebruiken, zodat de gegenereerde SQL wordt ondersteund. Dat gezegd hebbende, als u dit niet kunt doen, geef dan een opmerking bij het traceringsticket met details. We kunnen deze beslissing opnieuw bekijken op basis van feedback.
Extensie-informatie/metagegevens zijn verwijderd uit IDbContextOptionsExtension
Oud gedrag
IDbContextOptionsExtension
bevat methoden voor het verstrekken van metagegevens over de extensie.
Nieuw gedrag
Deze methoden zijn verplaatst naar een nieuwe DbContextOptionsExtensionInfo
abstracte basisklasse, die wordt geretourneerd vanuit een nieuwe eigenschap IDbContextOptionsExtension.Info
.
Waarom
In de releases van 2.0 tot 3.0 moesten we deze methoden meerdere keren toevoegen of wijzigen. Als u ze uitsplitst in een nieuwe abstracte basisklasse, is het eenvoudiger om dit soort wijzigingen aan te brengen zonder bestaande extensies te verbreken.
Maatregelen
Werk extensies bij om het nieuwe patroon te volgen.
Voorbeelden zijn te vinden in de vele implementaties van IDbContextOptionsExtension
voor verschillende soorten extensies in de EF Core-broncode.
De naam van LogQueryPossibleExceptionWithAggregateOperator is gewijzigd
Veranderen
RelationalEventId.LogQueryPossibleExceptionWithAggregateOperator
is gewijzigd in RelationalEventId.LogQueryPossibleExceptionWithAggregateOperatorWarning
.
Waarom
Hiermee wordt de naamgeving van deze waarschuwings gebeurtenis uitgelijnd met alle andere waarschuwingsevenementen.
Maatregelen
Gebruik de nieuwe naam. (Houd er rekening mee dat het gebeurtenis-id-nummer niet is gewijzigd.)
API verduidelijken voor namen van foreign key beperkingen
probleem met bijhouden #10730
Oud gedrag
Vóór EF Core 3.0 werden foreign key-constraint-namen eenvoudigweg "de naam" genoemd. Bijvoorbeeld:
var constraintName = myForeignKey.Name;
Nieuw gedrag
Vanaf EF Core 3.0 worden namen van foreign key-beperkingen nu aangeduid als de "beperkingsnaam". Bijvoorbeeld:
var constraintName = myForeignKey.ConstraintName;
Waarom
Deze wijziging brengt consistentie in naamgeving in dit gebied en verduidelijkt ook dat dit de naam is van de beperking voor refererende sleutels, en niet de kolom- of eigenschapsnaam waarop de refererende sleutel is gedefinieerd.
Oplossingen
Gebruik de nieuwe naam.
IRelationalDatabaseCreator.HasTables/HasTablesAsync is openbaar gemaakt
Oud gedrag
Vóór EF Core 3.0 werden deze methoden beveiligd.
Nieuw gedrag
Vanaf EF Core 3.0 zijn deze methoden openbaar.
Waarom
Deze methoden worden door EF gebruikt om te bepalen of een database is gemaakt, maar leeg is. Dit kan ook nuttig zijn van buiten EF bij het bepalen of migraties al dan niet moeten worden toegepast.
Oplossingen
Wijzig de toegankelijkheid van eventueel overschrijvingen.
Microsoft.EntityFrameworkCore.Design is nu een DevelopmentDependency-pakket
Oud gedrag
Vóór EF Core 3.0 was Microsoft.EntityFrameworkCore.Design een gewoon NuGet-pakket waarvan naar de assembly kan worden verwezen door projecten die ervan afhankelijk waren.
Nieuw gedrag
Vanaf EF Core 3.0 is het een DevelopmentDependency-pakket. Dit betekent dat de afhankelijkheid niet transitief naar andere projecten wordt doorgegeven en dat u standaard niet meer naar de assembly kunt verwijzen.
Waarom
Dit pakket is alleen bedoeld om te worden gebruikt tijdens het ontwerp. Geïmplementeerde toepassingen mogen er niet naar verwijzen. Door het pakket als een DevelopmentDependency in te stellen, wordt deze aanbeveling versterkt.
Beperkende maatregelen
Als u naar dit pakket wilt verwijzen om het ontwerptijdgedrag van EF Core te overschrijven, kunt u metagegevens van packageReference-items in uw project bijwerken.
<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>
Als het pakket transitief wordt verwezen via Microsoft.EntityFrameworkCore.Tools, moet u een expliciete PackageReference toevoegen aan het pakket om de metagegevens ervan te wijzigen. Een dergelijke expliciete verwijzing moet worden toegevoegd aan elk project waar de typen van het pakket nodig zijn.
SQLitePCL.raw bijgewerkt naar versie 2.0.0
Oud gedrag
Microsoft.EntityFrameworkCore.Sqlite was eerder afhankelijk van versie 1.1.12 van SQLitePCL.raw.
Nieuw gedrag
We hebben ons pakket bijgewerkt zodat het afhankelijk is van versie 2.0.0.
Waarom
Versie 2.0.0 van SQLitePCL.raw is gericht op .NET Standard 2.0. Het was eerder gericht op .NET Standard 1.1, waarvoor een grote sluiting van transitieve pakketten moest worden uitgevoerd.
Oplossingen
SQLitePCL.raw versie 2.0.0 bevat enkele belangrijke wijzigingen. Zie de releaseopmerkingen van voor meer informatie.
NetTopologySuite bijgewerkt naar versie 2.0.0
Oud gedrag
De ruimtelijke pakketten waren eerder afhankelijk van versie 1.15.1 van NetTopologySuite.
Nieuw gedrag
We hebben ons pakket bijgewerkt zodat het afhankelijk is van versie 2.0.0.
Waarom
Versie 2.0.0 van NetTopologySuite is bedoeld om verschillende bruikbaarheidsproblemen op te lossen die zijn opgetreden door EF Core-gebruikers.
Maatregelen
NetTopologySuite versie 2.0.0 bevat enkele belangrijke wijzigingen. Zie de releaseopmerkingen van voor meer informatie.
Microsoft.Data.SqlClient wordt gebruikt in plaats van System.Data.SqlClient
Oud gedrag
Microsoft.EntityFrameworkCore.SqlServer was eerder afhankelijk van System.Data.SqlClient.
Nieuw gedrag
We hebben ons pakket bijgewerkt zodat het afhankelijk is van Microsoft.Data.SqlClient.
Waarom
Microsoft.Data.SqlClient is het vlaggenschipstuurprogramma voor gegevenstoegang voor SQL Server, en System.Data.SqlClient is niet langer de focus van ontwikkeling. Enkele belangrijke functies, zoals Always Encrypted, zijn alleen beschikbaar op Microsoft.Data.SqlClient.
Oplossingen
Als uw code rechtstreeks afhankelijk is van System.Data.SqlClient, moet u deze wijzigen om in plaats daarvan te verwijzen naar Microsoft.Data.SqlClient; omdat de twee pakketten een zeer hoge mate van API-compatibiliteit behouden, mag dit alleen een eenvoudige pakket- en naamruimtewijziging zijn.
Er moeten meerdere dubbelzinnige zelfverwijzende relaties worden geconfigureerd
Oud gedrag
Een entiteitstype met meerdere zelfverwijzende unidirectionele navigatie-eigenschappen en overeenkomende FK's is onjuist geconfigureerd als één relatie. Bijvoorbeeld:
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; }
}
Nieuw gedrag
Dit scenario wordt nu gedetecteerd in het bouwen van modellen en er wordt een uitzondering gegenereerd die aangeeft dat het model dubbelzinnig is.
Waarom
Het resulterende model is dubbelzinnig en is waarschijnlijk onjuist voor dit geval.
Maatregelen
Gebruik de volledige configuratie van de relatie. Bijvoorbeeld:
modelBuilder
.Entity<User>()
.HasOne(e => e.CreatedBy)
.WithMany();
modelBuilder
.Entity<User>()
.HasOne(e => e.UpdatedBy)
.WithMany();
DbFunction.Schema dat null of een lege tekenreeks is, configureert deze in het standaardschema van het model
Oud gedrag
Een DbFunction geconfigureerd met schema als een lege tekenreeks is behandeld als ingebouwde functie zonder schema. Met de volgende code wordt bijvoorbeeld DatePart
CLR-functie toegewezen aan DATEPART
ingebouwde functie op SqlServer.
[DbFunction("DATEPART", Schema = "")]
public static int? DatePart(string datePartArg, DateTime? date) => throw new Exception();
Nieuw gedrag
Alle DbFunction-toewijzingen worden beschouwd als toegewezen aan door de gebruiker gedefinieerde functies. Daarom zou de lege tekenreekswaarde de functie in het standaardschema voor het model plaatsen. Dit kan het schema zijn dat expliciet is geconfigureerd via de fluent API modelBuilder.HasDefaultSchema()
of anders via dbo
.
Waarom
Voorheen was het leegmaken van een schema een manier om die functie te behandelen, maar die logica is alleen van toepassing op SqlServer, waarbij ingebouwde functies geen deel uitmaken van een schema.
Maatregelen
Configureer de vertaling van DbFunction handmatig om deze toe te wijzen aan een ingebouwde functie.
modelBuilder
.HasDbFunction(typeof(MyContext).GetMethod(nameof(MyContext.DatePart)))
.HasTranslation(args => SqlFunctionExpression.Create("DatePart", args, typeof(int?), null));
EF Core 3.0 richt zich op .NET Standard 2.1 in plaats van .NET Standard 2.0 Teruggedraaid
EF Core 3.0 is gericht op .NET Standard 2.1. Dit is een belangrijke wijziging die .NET Framework-toepassingen uitsluit. EF Core 3.1 heeft dit teruggedraaid en richt zich opnieuw op .NET Standard 2.0.
queryuitvoering wordt vastgelegd op foutopsporingsniveau Teruggedraaid
probleem met bijhouden #14523
Deze wijziging is teruggedraaid omdat met de nieuwe configuratie in EF Core 3.0 het logboekniveau voor elke gebeurtenis kan worden opgegeven door de toepassing. Als u bijvoorbeeld de logboekregistratie van SQL wilt overschakelen naar Debug
, configureert u expliciet het niveau in OnConfiguring
of AddDbContext
:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseSqlServer(connectionString)
.ConfigureWarnings(c => c.Log((RelationalEventId.CommandExecuting, LogLevel.Debug)));