Icke-bakåtkompatibla ändringar som ingår i EF Core 3.x
Följande API- och beteendeändringar kan bryta befintliga program när de uppgraderas till 3.x. Ändringar som vi förväntar oss endast påverkar databasleverantörer dokumenteras under leverantörändringar.
Sammanfattning
Ändringar med hög påverkan
LINQ-frågor utvärderas inte längre på klienten
Spårningsproblem #14935Se även problem #12795
Gammalt beteende
Innan 3.0, när EF Core inte kunde konvertera ett uttryck som var en del av en fråga till antingen SQL eller en parameter, utvärderade det automatiskt uttrycket på klienten. Som standard utlöste klientutvärdering av potentiellt dyra uttryck bara en varning.
Nytt beteende
Från och med 3.0 tillåter EF Core endast att uttryck i projektionen på den översta nivån (det sista Select()
-anropet i frågan) utvärderas på klienten.
När uttryck i någon annan del av frågan inte kan konverteras till antingen SQL eller en parameter genereras ett undantag.
Varför
Med automatisk klientutvärdering av frågor kan många frågor köras även om viktiga delar av dem inte kan översättas.
Det här beteendet kan leda till oväntat och potentiellt skadligt beteende som bara kan bli uppenbart i produktionen.
Ett villkor i ett Where()
-anrop som inte kan översättas kan till exempel göra att alla rader från tabellen överförs från databasservern och att filtret tillämpas på klienten.
Den här situationen kan enkelt gå oupptäckt om tabellen bara innehåller några rader under utveckling, men slår hårt när programmet flyttas till produktion, där tabellen kan innehålla miljontals rader.
Klientutvärderingsvarningar visade sig också vara för lätta att ignorera under utvecklingen.
Dessutom kan automatisk klientutvärdering leda till problem där förbättrad frågeöversättning för specifika uttryck orsakade oavsiktliga icke-bakåtkompatibla ändringar mellan versioner.
Åtgärder
Om en fråga inte kan översättas fullständigt skriver du antingen om frågan i ett formulär som kan översättas eller använder AsEnumerableAsync()
, ToListAsync()
eller liknande för att uttryckligen föra tillbaka data till klienten där den sedan kan bearbetas ytterligare med LINQ-to-Objects.
Ändringar med medelpåverkan
Entity Framework Core är inte längre en del av det delade ramverket för ASP.NET Core
Meddelanden om spårningsproblem #325
Gammalt beteende
Innan ASP.NET Core 3.0, när du lade till en paketreferens till Microsoft.AspNetCore.App
eller Microsoft.AspNetCore.All
, skulle den innehålla EF Core och några av EF Core-dataprovidrar som SQL Server-providern.
Nytt beteende
Från och med 3.0 innehåller det delade ASP.NET Core-ramverket inte EF Core eller några EF Core-dataproviders.
Varför
Innan den här ändringen krävdes olika steg för att skaffa EF Core beroende på om programmet riktade sig mot ASP.NET Core och SQL Server eller inte. Uppgradering av ASP.NET Core tvingade också till en uppgradering av EF Core och SQL Server-leverantören, vilket inte alltid är önskvärt.
Med den här ändringen är upplevelsen av att få EF Core densamma för alla leverantörer, .NET-implementeringar och programtyper som stöds. Utvecklare kan nu också styra exakt när EF Core- och EF Core-dataleverantörer uppgraderas.
Åtgärder
Om du vill använda EF Core i ett ASP.NET Core 3.0-program eller något annat program som stöds lägger du uttryckligen till en paketreferens till EF Core-databasprovidern som programmet ska använda.
EF Core-kommandoradsverktyget dotnet ef är inte längre en del av .NET Core SDK
Gammalt beteende
Före 3.0 inkluderades verktyget dotnet ef
i .NET Core SDK och var lätt att använda från kommandoraden från något projekt utan att kräva extra steg.
Nytt beteende
Från och med 3.0 innehåller .NET SDK inte verktyget dotnet ef
, så innan du kan använda det måste du uttryckligen installera det som ett lokalt eller globalt verktyg.
Varför
Med den här ändringen kan vi distribuera och uppdatera dotnet ef
som ett vanligt .NET CLI-verktyg på NuGet, vilket överensstämmer med det faktum att EF Core 3.0 också alltid distribueras som ett NuGet-paket.
Åtgärder
Om du vill kunna hantera migreringar eller skapa en DbContext
installerar du dotnet-ef
som ett globalt verktyg:
dotnet tool install --global dotnet-ef
Du kan också hämta ett lokalt verktyg när du återställer beroendena för ett projekt som deklarerar det som ett verktygsberoende med hjälp av en -verktygsmanifestfil.
Ändringar med låg påverkan
FromSql, ExecuteSql och ExecuteSqlAsync har bytt namn
Viktig
ExecuteSqlCommand
och ExecuteSqlCommandAsync
är inaktuella. Använd dessa metoder i stället.
Gammalt beteende
Före EF Core 3.0 överbelastades dessa metodnamn för att fungera med antingen en normal sträng eller en sträng som ska interpoleras till SQL och parametrar.
Nytt beteende
Från och med EF Core 3.0 använder du FromSqlRaw
, ExecuteSqlRaw
och ExecuteSqlRawAsync
för att skapa en parametriserad fråga där parametrarna skickas separat från frågesträngen.
Till exempel:
context.Products.FromSqlRaw(
"SELECT * FROM Products WHERE Name = {0}",
product.Name);
Använd FromSqlInterpolated
, ExecuteSqlInterpolated
och ExecuteSqlInterpolatedAsync
för att skapa en parametriserad fråga där parametrarna skickas som en del av en interpolerad frågesträng.
Till exempel:
context.Products.FromSqlInterpolated(
$"SELECT * FROM Products WHERE Name = {product.Name}");
Observera att båda frågorna ovan skapar samma parameteriserade SQL med samma SQL-parametrar.
Varför
Metodöverlagringar som den här gör det mycket enkelt att av misstag anropa råsträngsmetoden när avsikten var att anropa den interpolerade strängmetoden och tvärtom. Detta kan leda till att frågor inte parametriseras när de borde ha varit det.
Åtgärder
Växla om du vill använda de nya metodnamnen.
FromSql-metoden kan inte komponeras när den används med en lagrad procedur
Gammalt beteende
Innan EF Core 3.0 försökte "FromSql"-metoden identifiera om den överförda SQL:en kunde komponeras. Det genomförde en klientutvärdering när SQL var icke-sammansättbar, som en lagrad procedur. Följande fråga fungerade genom att köra den lagrade proceduren på servern och göra FirstOrDefault på klientsidan.
context.Products.FromSqlRaw("[dbo].[Ten Most Expensive Products]").FirstOrDefault();
Nytt beteende
Från och med EF Core 3.0 försöker EF Core inte parsa SQL. Så om du skriver efter FromSqlRaw/FromSqlInterpolated kommer EF Core att komponera SQL genom att skapa en underfråga. Så om du använder en lagrad procedur med sammansättning får du ett undantag för ogiltig SQL-syntax.
Varför
EF Core 3.0 stöder inte automatisk klientutvärdering, eftersom det var felbenäget enligt beskrivningen här.
Åtgärder
Om du använder en lagrad procedur i FromSqlRaw/FromSqlInterpolated vet du att den inte kan skapas, så du kan lägga till AsEnumerable
/AsAsyncEnumerable
direkt efter FromSql-metodanropet för att undvika komposition på serversidan.
context.Products.FromSqlRaw("[dbo].[Ten Most Expensive Products]").AsEnumerable().FirstOrDefault();
FromSql-metoder kan bara anges på frågerötter
Gammalt beteende
Före EF Core 3.0 kan FromSql
-metoden anges var som helst i frågan.
Nytt beteende
Från och med EF Core 3.0 kan de nya metoderna FromSqlRaw
och FromSqlInterpolated
(som ersätter FromSql
) endast anges på frågerötter, d.v.s. direkt på DbSet<>
. Om du försöker ange dem någon annanstans resulterar det i ett kompileringsfel.
Varför
Att ange FromSql
någon annanstans än på en DbSet
inte hade någon ytterligare betydelse eller mervärde och kan orsaka tvetydighet i vissa scenarier.
Åtgärder
FromSql
-anrop bör flyttas så att de är direkt på den DbSet
de gäller för.
Frågor utan spårning utför inte längre identitetsmatchning
Gammalt beteende
Före EF Core 3.0 skulle samma entitetsinstans användas för varje förekomst av en entitet med en viss typ och ID. Detta matchar beteendet för spårning av sökfrågor. Till exempel den här frågan:
var results = await context.Products.Include(e => e.Category).AsNoTracking().ToListAsync();
returnerar samma Category
instans för varje Product
som är associerad med den angivna kategorin.
Nytt beteende
Från och med EF Core 3.0 skapas olika entitetsinstanser när en entitet med en viss typ och ID påträffas på olika platser i den returnerade grafen. Frågan ovan returnerar till exempel nu en ny Category
instans för varje Product
även när två produkter är associerade med samma kategori.
Varför
Identitetsmatchning (dvs. att fastställa att en entitet har samma typ och ID som en tidigare påträffad entitet) ger ytterligare prestanda och minnesomkostnader. Detta går vanligtvis emot anledningen till varför frågor utan spårning används från början. Även om identitetsmatchning ibland kan vara användbar, behövs det inte om entiteterna ska serialiseras och skickas till en klient, vilket är vanligt för frågor utan spårning.
Åtgärder
Använd en spårningsfråga om identitetsmatchning krävs.
Temporära nyckelvärden anges inte längre till entitetsinstanser
Gammalt beteende
Före EF Core 3.0 tilldelades tillfälliga värden till alla nyckelegenskaper som senare skulle ha ett verkligt värde som genererades av databasen. Vanligtvis var dessa temporära värden stora negativa tal.
Nytt beteende
Från och med 3.0 lagrar EF Core det tillfälliga nyckelvärdet som en del av entitetens spårningsinformation och lämnar själva nyckelegenskapen oförändrad.
Varför
Den här ändringen gjordes för att förhindra att tillfälliga nyckelvärden felaktigt blir permanenta när en entitet som tidigare har spårats av någon DbContext
instans flyttas till en annan DbContext
instans.
Åtgärder
Program som tilldelar primärnyckelvärden till externa nycklar för att bilda associationer mellan entiteter kan bero på det gamla beteendet om de primära nycklarna är butiksgenererade och tillhör entiteter i Added
tillstånd.
Detta kan undvikas genom att:
- Använder inte butiksgenererade nycklar.
- Ange navigeringsegenskaper för att upprätta relationer i stället för att ange värden för utländsk nyckel.
- Hämta de faktiska temporära nyckelvärdena från entitetens spårningsinformation.
Till exempel returnerar
context.Entry(blog).Property(e => e.Id).CurrentValue
det tillfälliga värdet även omblog.Id
inte har angetts.
DetectChanges respekterar butiksgenererade nyckelvärden
Gammalt beteende
Före EF Core 3.0 skulle en ospårad entitet som hittas av DetectChanges
spåras i tillståndet Added
och infogas som en ny rad när SaveChanges
anropas.
Nytt beteende
Från och med EF Core 3.0, om en entitet använder genererade nyckelvärden och ett visst nyckelvärde anges, spåras entiteten i Modified
tillstånd.
Det innebär att en rad för entiteten antas finnas och uppdateras när SaveChanges
anropas.
Om nyckelvärdet inte har angetts, eller om entitetstypen inte använder genererade nycklar, spåras den nya entiteten fortfarande som Added
som i tidigare versioner.
Varför
Den här ändringen gjordes för att göra det enklare och mer konsekvent att arbeta med frånkopplade entitetsdiagram när du använder butiksgenererade nycklar.
Åtgärder
Den här ändringen kan bryta ett program om en entitetstyp har konfigurerats för att använda genererade nycklar, men nyckelvärden anges uttryckligen för nya instanser. Korrigeringen är att uttryckligen konfigurera nyckelegenskaperna så att de inte använder genererade värden. Till exempel med api:et fluent:
modelBuilder
.Entity<Blog>()
.Property(e => e.Id)
.ValueGeneratedNever();
Eller med dataanteckningar:
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string Id { get; set; }
Kaskadborttagningar sker nu omedelbart som standard
Gammalt beteende
Före 3.0 tillämpade EF Core sammanhängande åtgärder (ta bort beroende entiteter när ett obligatoriskt huvudnamn tas bort eller när relationen till ett obligatoriskt huvudnamn har brutits) inte förrän SaveChanges anropades.
Nytt beteende
Från och med 3.0 tillämpar EF Core sammanhängande åtgärder så snart utlösarvillkoret har identifierats.
Om du till exempel anropar context.Remove()
för att ta bort en huvudentitet kommer alla spårade relaterade nödvändiga beroenden också att ställas in på Deleted
omedelbart.
Varför
Den här ändringen gjordes för att förbättra upplevelsen för databindnings- och granskningsscenarier där det är viktigt att förstå vilka entiteter som ska tas bort innanSaveChanges
anropas.
Åtgärder
Det tidigare beteendet kan återställas via inställningarna på context.ChangeTracker
.
Till exempel:
context.ChangeTracker.CascadeDeleteTiming = CascadeTiming.OnSaveChanges;
context.ChangeTracker.DeleteOrphansTiming = CascadeTiming.OnSaveChanges;
Ivrig inläsning av relaterade entiteter sker nu i en enda fråga
Gammalt beteende
Före 3.0 orsakade ivrig inläsning av samlingsnavigeringar via Include
operatorer att flera frågor genererades på relationsdatabasen, en för varje relaterad entitetstyp.
Nytt beteende
Från och med 3.0 genererar EF Core en enda fråga med JOIN på relationsdatabaser.
Varför
Att skicka flera förfrågningar för att implementera en enda LINQ-fråga orsakade många problem, inklusive prestandaproblem eftersom flera databasanrop var nödvändiga, och problem med datakonsekvens eftersom varje begäran kunde observera ett annat tillstånd för databasen.
Åtgärder
Även om detta tekniskt sett inte är en bakåtkompatibel ändring kan det ha en betydande effekt på applikationens prestanda när en enskild fråga innehåller ett stort antal Include
-operatorer vid samlingsnavigeringar.
Se den här kommentaren för mer information och för att skriva om frågor på ett mer effektivt sätt.
**
DeleteBehavior.Restrict har renare semantik
Gammalt beteende
Före 3.0 skapade DeleteBehavior.Restrict
främmande nycklar i databasen med Restrict
semantik, men ändrade även intern justering på ett otydligt sätt.
Nytt beteende
Från och med 3.0 ser DeleteBehavior.Restrict
till att utländska nycklar skapas med Restrict
semantik; det vill säga: inga kaskader; kastar ett undantag vid begränsningsöverträdelser, utan att påverka EF:s interna korrigering.
Varför
Denna ändring gjordes för att förbättra upplevelsen för att använda DeleteBehavior
på ett intuitivt sätt, utan oväntade biverkningar.
Åtgärder
Det tidigare beteendet kan återställas med hjälp av DeleteBehavior.ClientNoAction
.
Frågetyper konsolideras med entitetstyper
Gammalt beteende
Före EF Core 3.0 var frågetyper ett sätt att fråga efter data som inte definierar en primärnyckel på ett strukturerat sätt. Det vill säga en frågetyp användes för att mappa entitetstyper utan nycklar (mer sannolikt från en vy, men eventuellt från en tabell) medan en vanlig entitetstyp användes när en nyckel var tillgänglig (mer sannolikt från en tabell, men möjligen från en vy).
Nytt beteende
En frågetyp blir nu bara en entitetstyp utan primärnyckel. Nyckellösa entitetstyper har samma funktioner som frågetyper i tidigare versioner.
Varför
Den här ändringen gjordes för att minska förvirringen kring syftet med frågetyper. Mer specifikt är de nyckellösa entitetstyper och de är i sig skrivskyddade på grund av detta, men de bör inte användas bara för att en entitetstyp måste vara skrivskyddad. På samma sätt mappas de ofta till vyer, men det beror bara på att vyer ofta inte definierar nycklar.
Åtgärder
Följande delar av API:et är nu föråldrade:
-
ModelBuilder.Query<>()
– I stället måsteModelBuilder.Entity<>().HasNoKey()
anropas för att markera en entitetstyp som saknar nycklar. Detta skulle fortfarande inte konfigureras enligt konventionen för att undvika felkonfiguration när en primärnyckel förväntas men inte följer konventionen. -
DbQuery<>
– I stället skaDbSet<>
användas. -
DbContext.Query<>()
– I stället skaDbContext.Set<>()
användas. -
IQueryTypeConfiguration<TQuery>
– I stället skaIEntityTypeConfiguration<TEntity>
användas.
Note
På grund av ett problem i 3.x vid frågor mot nyckellösa entiteter som har alla egenskaper inställda på null
returneras en null
i stället för en entitet, om det här problemet gäller för ditt scenario lägger du också till logik för att hantera null
i resultat.
Konfigurations-API för ägda typrelationer har ändrats
Spårningsproblem #12444Spårningsproblem #9148Spårningsproblem #14153
Gammalt beteende
Före EF Core 3.0 utfördes konfigurationen av den ägda relationen direkt efter OwnsOne
- eller OwnsMany
-anropet.
Nytt beteende
Från och med EF Core 3.0 finns det nu fluent API för att konfigurera en navigeringsegenskap för ägaren med hjälp av WithOwner()
.
Till exempel:
modelBuilder.Entity<Order>.OwnsOne(e => e.Details).WithOwner(e => e.Order);
Konfigurationen som är relaterad till relationen mellan ägare och ägd bör nu kopplas efter WithOwner()
på samma sätt som andra relationer konfigureras.
Konfigurationen för den ägda typen skulle fortfarande vara länkad efter OwnsOne()/OwnsMany()
.
Till exempel:
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
});
});
Om du anropar Entity()
, HasOne()
eller Set()
med ett mål av ägartyp utlöser du nu ett undantag.
Varför
Den här ändringen gjordes för att skapa en tydligare åtskillnad mellan att konfigurera själva den ägda typen och relationen till för den ägda typen.
Detta i sin tur tar bort tvetydighet och förvirring kring metoder som HasForeignKey
.
Åtgärder
Ändra konfigurationen av ägda typrelationer så att den nya API-ytan används enligt exemplet ovan.
Beroende entiteter som delar tabellen med huvudnamnet är nu valfria
Gammalt beteende
Tänk på följande modell:
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; }
}
Om OrderDetails
ägs av Order
eller uttryckligen mappas till samma tabell innan EF Core 3.0 krävs alltid en OrderDetails
instans när du lägger till en ny Order
.
Nytt beteende
Från och med 3.0 kan EF Core lägga till en Order
utan en OrderDetails
och mappar alla OrderDetails
-egenskaper förutom primärnyckeln till nullable kolumner.
När du frågar i EF Core-uppsättningar, ställs OrderDetails
till null
om någon av dess nödvändiga egenskaper saknar ett värde, eller om den inte har några nödvändiga egenskaper förutom den primära nyckeln och alla egenskaper är null
.
Åtgärder
Om din modell har en tabelldelning som är beroende av alla valfria kolumner, men navigeringen som pekar på den inte förväntas vara null
bör programmet ändras för att hantera ärenden när navigeringen är null
. Om detta inte är möjligt ska en obligatorisk egenskap läggas till i entitetstypen, eller så bör minst en egenskap ha ett icke-null
värde som tilldelats den.
Alla entiteter som delar en tabell med en samtidighetstokenkolumn måste mappa den till en egenskap
Gammalt beteende
Tänk på följande modell:
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");
}
Innan EF Core 3.0, om OrderDetails
ägs av Order
eller uttryckligen mappas till samma tabell, kommer en uppdatering av endast OrderDetails
inte att uppdatera Version
-värdet på klienten och nästa uppdatering kommer att misslyckas.
Nytt beteende
Från och med 3.0 sprider EF Core det nya Version
värdet till Order
om det äger OrderDetails
. Annars utlöses ett undantag under modellverifieringen.
Varför
Den här ändringen gjordes för att undvika ett inaktuellt samtidighetstokenvärde när endast en av entiteterna som mappats till samma tabell uppdateras.
Åtgärder
Alla entiteter som delar tabellen måste innehålla en egenskap som är mappad till kolumnen samtidighetstoken. Det är möjligt att skapa en i skuggtillstånd:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<OrderDetails>()
.Property<byte[]>("Version").IsRowVersion().HasColumnName("Version");
}
Ägda entiteter kan inte förfrågas utan att använda ägarens spårningsfråga
Gammalt beteende
Före EF Core 3.0 kan ägda entiteter frågas efter som vilken annan navigering som helst.
context.People.Select(p => p.Address);
Nytt beteende
Från och med 3.0 genererar EF Core om en spårningsfråga projicerar en ägd entitet utan ägaren.
Varför
Ägda entiteter kan inte manipuleras utan ägaren, så i de allra flesta fall är det ett fel att fråga dem på det här sättet.
Åtgärder
Om den ägda entiteten ska spåras för att ändras på något sätt senare bör ägaren inkluderas i frågan.
Lägg annars till ett AsNoTracking()
-anrop:
context.People.Select(p => p.Address).AsNoTracking();
Ärvda egenskaper från omappade typer mappas nu till en enda kolumn för alla härledda typer
Gammalt beteende
Tänk på följande modell:
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>();
}
Före EF Core 3.0 mappas egenskapen ShippingAddress
till separata kolumner för BulkOrder
och Order
som standard.
Nytt beteende
Från och med 3.0 skapar EF Core bara en kolumn för ShippingAddress
.
Varför
Det gamla beteendet var oväntat.
Åtgärder
Egenskapen kan fortfarande mappas explicit till en separat kolumn för de härledda typerna:
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");
}
Konventionen för utländska nycklar matchar inte längre samma namn som huvudegenskapen.
Gammalt beteende
Tänk på följande modell:
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; }
}
Före EF Core 3.0 skulle egenskapen CustomerId
användas för främmande nyckel enligt konventionen.
Men om Order
är en ägd typ skulle detta också göra CustomerId
till den primära nyckeln, och detta är vanligtvis inte förväntningen.
Nytt beteende
Från och med 3.0 försöker EF Core inte använda egenskaper för främmande nycklar som standard om de har samma namn som huvudegenskapen. Huvudtypens namn som är sammanfogat med huvudegenskapens namn och navigeringsnamnet som är sammanfogat med huvudegenskapens namn matchar fortfarande mönstren. Till exempel:
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; }
}
Varför
Den här ändringen gjordes för att undvika att felaktigt definiera en primärnyckelegenskap för den ägda typen.
Åtgärder
Om egenskapen var avsedd att vara den utländska nyckeln och därmed en del av den primära nyckeln, bör du uttryckligen konfigurera den som sådan.
Databasanslutningen stängs nu om den inte används längre innan TransactionScope har slutförts
Gammalt beteende
Om kontexten öppnar anslutningen i en TransactionScope
före EF Core 3.0 förblir anslutningen öppen medan den aktuella TransactionScope
är aktiv.
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();
}
}
Nytt beteende
Från och med 3.0 stänger EF Core anslutningen så snart den har använts.
Varför
Med den här ändringen kan du använda flera kontexter i samma TransactionScope
. Det nya beteendet matchar även EF6.
Förmildrande åtgärder
**
Om anslutningen måste förbli öppen, genom att explicit anropa OpenConnection()
ser man till att EF Core inte stänger den i förtid.
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();
}
}
Varje egenskap använder oberoende minnesintern heltalsnyckelgenerering
Gammalt beteende
Före EF Core 3.0 användes en delad värdegenerator för alla heltalsnyckelegenskaper i minnet.
Nytt beteende
Från och med EF Core 3.0 hämtar varje heltalsnyckelegenskap sin egen värdegenerator när du använder den minnesinterna databasen. Om databasen också tas bort återställs nyckelgenereringen för alla tabeller.
Varför
Den här ändringen gjordes för att justera minnesintern nyckelgenerering närmare till verklig databasnyckelgenerering och för att förbättra möjligheten att isolera tester från varandra när du använder minnesintern databas.
Åtgärder
Detta kan bryta ett program som förlitar sig på specifika minnesinterna nyckelvärden som ska anges. Överväg att i stället inte förlita dig på specifika nyckelvärden eller uppdatera för att matcha det nya beteendet.
Bakfält används som standard
Gammalt beteende
Före 3.0, även om bakgrundsfältet för en egenskap var känt, skulle EF Core fortfarande som standard läsa och skriva egenskapsvärdet med hjälp av egenskaps getter- och setter-metoderna. Undantaget till detta var frågekörning, där bakgrundsfältet skulle anges direkt om det är känt.
Nytt beteende
Från och med EF Core 3.0, om bakgrundsfältet för en egenskap är känt, läser och skriver EF Core alltid egenskapen med hjälp av bakgrundsfältet. Detta kan orsaka en programbrytning om programmet förlitar sig på ytterligare beteende som kodas i metoden getter eller setter.
Varför
Den här ändringen gjordes för att förhindra att EF Core felaktigt utlöser affärslogik som standard när databasåtgärder som involverar entiteterna utförs.
Åtgärder
Beteendet före 3.0 kan återställas via konfigurationen av egenskapens åtkomstläge på ModelBuilder
.
Till exempel:
modelBuilder.UsePropertyAccessMode(PropertyAccessMode.PreferFieldDuringConstruction);
Kasta om flera kompatibla bakgrundsfält hittas
Gammalt beteende
Om flera fält matchade reglerna för att hitta bakgrundsfältet för en egenskap före EF Core 3.0 skulle ett fält väljas baserat på någon prioritetsordning. Detta kan göra att fel fält används i tvetydiga fall.
Nytt beteende
Från och med EF Core 3.0 genereras ett undantag om flera fält matchas med samma egenskap.
Varför
Den här ändringen gjordes för att undvika tyst användning av ett fält över ett annat när endast ett kan vara korrekt.
Åtgärder
Egenskaper med tvetydiga bakgrundsfält måste ha det fält som ska användas uttryckligen. Du kan till exempel använda API:et fluent:
modelBuilder
.Entity<Blog>()
.Property(e => e.Id)
.HasField("_id");
Namn på endast fältegenskaper ska matcha fältnamnet
Gammalt beteende
Före EF Core 3.0 kunde en egenskap anges med ett strängvärde och om ingen egenskap med det namnet hittades på .NET-typen skulle EF Core försöka matcha den med ett fält med hjälp av konventionsregler.
private class Blog
{
private int _id;
public string Name { get; set; }
}
modelBuilder
.Entity<Blog>()
.Property("Id");
Nytt beteende
Från och med EF Core 3.0 måste en endast fältegenskap matcha fältnamnet exakt.
modelBuilder
.Entity<Blog>()
.Property("_id");
Varför
Den här ändringen gjordes för att undvika att använda samma fält för två egenskaper med namnet på samma sätt. Matchningsreglerna för endast fältegenskaper blir desamma som för egenskaper som mappas till CLR-egenskaper.
Åtgärder
Endast fältegenskaper måste namnges på samma sätt som det fält som de mappas till. I en framtida version av EF Core efter 3.0 planerar vi att återaktivera explicit konfiguration av ett fältnamn som skiljer sig från egenskapsnamnet (se problem #15307):
modelBuilder
.Entity<Blog>()
.Property("Id")
.HasField("_id");
AddDbContext/AddDbContextPool anropar inte längre AddLogging och AddMemoryCache
Gammalt beteende
Innan EF Core 3.0 skulle anrop till AddDbContext
eller AddDbContextPool
också registrera loggnings- och minnescachetjänster med DI via anrop till AddLogging och AddMemoryCache.
Nytt beteende
Från och med EF Core 3.0 kommer AddDbContext
och AddDbContextPool
inte längre att registrera dessa tjänster med beroendeinjektion (DI).
Varför
EF Core 3.0 kräver inte att dessa tjänster finns i programmets DI-container. Men om ILoggerFactory
är registrerad i programmets DI-container används den fortfarande av EF Core.
Åtgärder
Om programmet behöver dessa tjänster registrerar du dem uttryckligen med DI-containern med hjälp av AddLogging eller AddMemoryCache.
AddEntityFramework* lägger till IMemoryCache med en storleksgräns
Gammalt beteende
Innan EF Core 3.0 skulle anrop av AddEntityFramework*
metoder också registrera cachelagringstjänster för minne med DI utan storleksgräns.
Nytt beteende
Från och med EF Core 3.0 registrerar AddEntityFramework*
en IMemoryCache-tjänst med en storleksgräns. Om andra tjänster som läggs till efteråt är beroende av IMemoryCache kan de snabbt nå standardgränsen som orsakar undantag eller försämrad prestanda.
Varför
Om du använder IMemoryCache utan en gräns kan det leda till okontrollerad minnesanvändning om det finns en bugg i cachelagringslogik för frågor eller om frågorna genereras dynamiskt. Om du har en standardgräns minimeras en potentiell DoS-attack.
Åtgärder
I de flesta fall är det inte nödvändigt att anropa AddEntityFramework*
om AddDbContext
eller AddDbContextPool
också anropas. Därför är den bästa lösningen att ta bort AddEntityFramework*
-anropet.
Om programmet behöver dessa tjänster registrerar du en IMemoryCache-implementering explicit med DI-containern i förväg med hjälp av AddMemoryCache-.
DbContext.Entry utför nu en lokal ändringsdetektion
Gammalt beteende
Innan EF Core 3.0 skulle ett anrop av DbContext.Entry
resultera i att ändringar identifierades för alla spårade entiteter.
Detta säkerställde att tillståndet som exponerades i EntityEntry
var up-to-date.
Nytt beteende
Från och med EF Core 3.0 försöker anropa DbContext.Entry
nu bara identifiera ändringar i den angivna entiteten och eventuella spårade huvudobjektentiteter som är relaterade till den.
Det innebär att ändringar någon annanstans kanske inte har identifierats genom att anropa den här metoden, vilket kan påverka programtillståndet.
Observera att om ChangeTracker.AutoDetectChangesEnabled
är inställt på false
inaktiveras även den här lokala ändringsidentifieringen.
Andra metoder som orsakar ändringsdetektering – till exempel ChangeTracker.Entries
och SaveChanges
– orsakar fortfarande en fullständig DetectChanges
för alla spårade entiteter.
Varför
Den här ändringen gjordes för att förbättra standardprestandan för att använda context.Entry
.
Åtgärder
Anropa ChangeTracker.DetectChanges()
explicit innan du anropar Entry
för att säkerställa beteendet före 3.0.
Sträng- och byte-array-nycklar genereras inte av klienten som standard
Gammalt beteende
Före EF Core 3.0 kan string
och byte[]
nyckelegenskaper användas utan att uttryckligen ange ett värde som inte är null.
I sådana fall genereras nyckelvärdet på klienten som en GUID, serialiserat till bytes för byte[]
.
Nytt beteende
Från och med EF Core 3.0 genereras ett undantag som anger att inget nyckelvärde har angetts.
Varför
Den här ändringen gjordes eftersom klientgenererade string
/byte[]
värden i allmänhet inte är användbara, och standardbeteendet gjorde det svårt att resonera om genererade nyckelvärden på ett vanligt sätt.
Åtgärder
Beteendet före 3.0 kan hämtas genom att uttryckligen ange att nyckelegenskaperna ska använda genererade värden om inget annat värde som inte är null har angetts. Till exempel med api:et fluent:
modelBuilder
.Entity<Blog>()
.Property(e => e.Id)
.ValueGeneratedOnAdd();
Eller med dataanteckningar:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }
ILoggerFactory är nu en begränsad tjänst
Gammalt beteende
Innan EF Core 3.0 registrerades ILoggerFactory
som en singleton-tjänst.
Nytt beteende
Från och med EF Core 3.0 är ILoggerFactory
nu registrerad som scope-bunden.
Varför
Den här ändringen gjordes för att tillåta association av en loggare med en DbContext
-instans, vilket möjliggör andra funktioner och tar bort vissa fall av patologiskt beteende, till exempel en explosion av interna tjänstleverantörer.
Åtgärder
Den här ändringen bör inte påverka programkoden om den inte registrerar och använder anpassade tjänster på den interna EF Core-tjänstleverantören.
Det här är inte vanligt.
I dessa fall fungerar det mesta fortfarande, men alla singleton-tjänster som var beroende av ILoggerFactory
måste ändras för att få ILoggerFactory
på ett annat sätt.
Om du stöter på sådana här situationer kan du skicka in ett problem på EF Core GitHub-utfärdare för att meddela oss hur du använder ILoggerFactory
så att vi bättre kan förstå hur vi inte kan bryta detta igen i framtiden.
Proxyservrar med lat inläsning förutsätter inte längre att navigeringsegenskaperna är helt inlästa
Gammalt beteende
Innan EF Core 3.0, när en DbContext
togs bort, fanns det inget sätt att veta om en viss navigeringsegenskap på en entitet som hämtats från den kontexten var helt inläst eller inte.
Proxyservrar förutsätter i stället att en referensnavigering läses in om den har ett värde som inte är null och att en samlingsnavigering läses in om den inte är tom.
I dessa fall skulle det vara en no-opatt försöka använda lazy loading.
Nytt beteende
Från och med EF Core 3.0 håller proxyservrar reda på om en navigeringsegenskap läses in eller inte. Det innebär att försök att komma åt en navigeringsegenskap som läses in när kontexten har tagits bort alltid är en no-op, även när den inlästa navigeringen är tom eller null. Om du försöker komma åt en navigeringsegenskap som inte läses in genereras ett undantag om kontexten tas bort även om navigeringsegenskapen är en icke-tom samling. Om den här situationen uppstår innebär det att programkoden försöker använda lazy-loading vid en ogiltig tidpunkt, och programmet bör ändras för att inte göra detta.
Varför
Den här ändringen gjordes för att göra beteendet konsekvent och korrekt vid försök att fördröja inläsningen på en avvecklad DbContext
-instans.
Åtgärder
Uppdatera programkoden så att den inte försöker sen inladdning med en frigjord kontext, eller konfigurera detta som en no-op enligt beskrivningen i undantagsmeddelandet.
Överdrivet skapande av interna tjänstleverantörer är nu ett fel som standard
Gammalt beteende
Innan EF Core 3.0 loggas en varning för ett program som skapar ett patologiskt antal interna tjänstleverantörer.
Nytt beteende
Från och med EF Core 3.0 behandlas denna varning nu som ett fel och ett undantag kastas.
Varför
Den här ändringen gjordes för att skapa bättre programkod genom att exponera det här patologiska fallet mer explicit.
Åtgärder
Den lämpligaste åtgärden när du stöter på det här felet är att förstå rotorsaken och sluta skapa så många interna tjänstleverantörer.
Felet kan dock konverteras tillbaka till en varning (eller ignoreras) via konfigurationen på DbContextOptionsBuilder
.
Till exempel:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.ConfigureWarnings(w => w.Log(CoreEventId.ManyServiceProvidersCreatedWarning));
}
Nytt beteende för HasOne/HasMany som anropas med en enda sträng
Gammalt beteende
Innan EF Core 3.0 tolkades kodanropet HasOne
eller HasMany
med en enda sträng på ett förvirrande sätt.
Till exempel:
modelBuilder.Entity<Samurai>().HasOne("Entrance").WithOne();
Koden ser ut att relatera Samurai
till någon annan entitetstyp med hjälp av Entrance
navigeringsegenskap, som kan vara privat.
I själva verket försöker den här koden skapa en relation till någon entitetstyp som kallas Entrance
utan navigeringsegenskap.
Nytt beteende
Från och med EF Core 3.0 gör koden ovan nu vad den borde ha gjort tidigare.
Varför
Det gamla beteendet var mycket förvirrande, särskilt när du läste konfigurationskoden och letade efter fel.
Åtgärder
Detta bryter bara program som uttryckligen konfigurerar relationer med hjälp av strängar för typnamn och utan att uttryckligen ange navigeringsegenskapen.
Det här är inte vanligt.
Det tidigare beteendet kan uppnås genom att uttryckligen skicka null
för navigeringsegenskapens namn.
Till exempel:
modelBuilder.Entity<Samurai>().HasOne("Some.Entity.Type.Name", null).WithOne();
Returtypen för flera asynkrona metoder har ändrats från Aktivitet till ValueTask
Gammalt beteende
Följande asynkrona metoder returnerade tidigare en Task<T>
:
DbContext.FindAsync()
DbSet.FindAsync()
DbContext.AddAsync()
DbSet.AddAsync()
-
ValueGenerator.NextValueAsync()
(och derivatklasser)
Nytt beteende
De ovan nämnda metoderna returnerar nu en ValueTask<T>
över samma T
som tidigare.
Varför
Den här ändringen minskar antalet heapallokeringar som uppstår när du anropar dessa metoder, vilket förbättrar den allmänna prestandan.
Åtgärder
Program som bara väntar på api:erna ovan behöver bara kompileras om – inga källändringar krävs.
En mer komplex användning (t.ex. att skicka den returnerade Task
till Task.WhenAny()
) kräver vanligtvis att den returnerade ValueTask<T>
konverteras till en Task<T>
genom att anropa AsTask()
på den.
Observera att detta negerar allokeringsminskningen som den här ändringen medför.
Anmärkningen Relational:TypeMapping är nu endast TypeMapping
Gammalt beteende
Anteckningsnamnet för typmappningsanteckningar var "Relational:TypeMapping".
Nytt beteende
Anteckningsnamnet för typmappningsanteckningar är nu "TypeMapping".
Varför
Typmappningar används nu för mer än bara relationsdatabasprovidrar.
Åtgärder
Detta kommer endast att bryta program som direkt använder typmappningen som en annotering, vilket inte är vanligt. Den lämpligaste åtgärden att åtgärda är att använda API-ytan för att komma åt typmappningar i stället för att använda kommentaren direkt.
ToTable på en härledd typ genererar ett undantag
Gammalt beteende
Innan EF Core 3.0 skulle ToTable()
, som anropades på en härledd typ, ignoreras eftersom arvsmappningsstrategin var begränsad till TPH, vilket inte är tillämpligt här.
Nytt beteende
Från och med EF Core 3.0 och som förberedelse för att lägga till TPT- och TPC-stöd i en senare version, utlöser ToTable()
som anropas för en härledd typ nu ett undantag för att undvika en oväntad mappningsändring i framtiden.
Varför
För närvarande är det inte giltigt att mappa en härledd typ till en annan tabell. Den här ändringen undviker att gå sönder i framtiden när det blir en accepterad sak att göra.
Åtgärder
Ta bort alla försök att mappa härledda typer till andra tabeller.
ForSqlServerHasIndex ersatt med HasIndex
Gammalt beteende
Före EF Core 3.0 gav ForSqlServerHasIndex().ForSqlServerInclude()
ett sätt att konfigurera kolumner som används med INCLUDE
.
Nytt beteende
Från och med EF Core 3.0 stöds nu användning av Include
på ett index på relationsnivå.
Använd HasIndex().ForSqlServerInclude()
.
Varför
Den här ändringen gjordes för att konsolidera API:et för index med Include
till en plats för alla databasprovidrar.
Åtgärder
Använd det nya API:et, som du ser ovan.
Metadata-API-ändringar
Nytt beteende
Följande egenskaper konverterades till tilläggsmetoder:
-
IEntityType.QueryFilter
->GetQueryFilter()
-
IEntityType.DefiningQuery
->GetDefiningQuery()
-
IProperty.IsShadowProperty
->IsShadowProperty()
-
IProperty.BeforeSaveBehavior
->GetBeforeSaveBehavior()
-
IProperty.AfterSaveBehavior
->GetAfterSaveBehavior()
Varför
Den här ändringen förenklar implementeringen av ovan nämnda gränssnitt.
Åtgärder
Använd de nya tilläggsmetoderna.
Ändringar i providerspecifikt metadata-API
Nytt beteende
De providerspecifika tilläggsmetoderna plattas ut:
-
IProperty.Relational().ColumnName
->IProperty.GetColumnName()
-
IEntityType.SqlServer().IsMemoryOptimized
->IEntityType.IsMemoryOptimized()
-
PropertyBuilder.UseSqlServerIdentityColumn()
->PropertyBuilder.UseIdentityColumn()
Varför
Den här ändringen förenklar genomförandet av de ovannämnda tilläggsmetoderna.
Åtgärder
Använd de nya tilläggsmetoderna.
EF Core skickar inte längre pragma för SQLite FK-tillämpning
Gammalt beteende
Innan EF Core 3.0 skickar EF Core PRAGMA foreign_keys = 1
när en anslutning till SQLite öppnas.
Nytt beteende
Från och med EF Core 3.0 skickar EF Core inte längre PRAGMA foreign_keys = 1
när en anslutning till SQLite öppnas.
Varför
Den här ändringen gjordes eftersom EF Core använder SQLitePCLRaw.bundle_e_sqlite3
som standard, vilket i sin tur innebär att FK-tillämpningen är aktiverad som standard och inte behöver aktiveras uttryckligen varje gång en anslutning öppnas.
Åtgärder
Främmande nycklar är aktiverade som standard i SQLitePCLRaw.bundle_e_sqlite3, vilket används för EF Core.
I andra fall kan främmande nycklar aktiveras genom att ange Foreign Keys=True
i anslutningssträngen.
Microsoft.EntityFrameworkCore.Sqlite är nu beroende av SQLitePCLRaw.bundle_e_sqlite3
Gammalt beteende
Före EF Core 3.0 använde EF Core SQLitePCLRaw.bundle_green
.
Nytt beteende
Från och med EF Core 3.0 använder EF Core SQLitePCLRaw.bundle_e_sqlite3
.
Varför
Den här ändringen gjordes så att den version av SQLite som används på iOS överensstämmer med andra plattformar.
Åtgärder
Om du vill använda den interna SQLite-versionen på iOS konfigurerar du Microsoft.Data.Sqlite
att använda ett annat SQLitePCLRaw
paket.
Guid-värden lagras nu som TEXT på SQLite
Gammalt beteende
Guid-värden lagrades tidigare som BLOB-värden på SQLite.
Nytt beteende
Guid-värden lagras nu som TEXT.
Varför
Det binära formatet för Guids är inte standardiserat. Om du lagrar värdena som TEXT blir databasen mer kompatibel med andra tekniker.
Åtgärder
Du kan migrera befintliga databaser till det nya formatet genom att köra SQL på följande sätt.
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';
I EF Core kan du också fortsätta att använda det tidigare beteendet genom att konfigurera en värdekonverterare för dessa egenskaper.
modelBuilder
.Entity<MyEntity>()
.Property(e => e.GuidProperty)
.HasConversion(
g => g.ToByteArray(),
b => new Guid(b));
Microsoft.Data.Sqlite kan fortfarande läsa Guid-värden från både BLOB- och TEXT-kolumner. Men eftersom standardformatet för parametrar och konstanter har ändrats måste du förmodligen vidta åtgärder för de flesta scenarier som involverar Guids.
Teckenvärden lagras nu som TEXT på SQLite
Gammalt beteende
Teckenvärden lagrades tidigare som INTEGER-värden på SQLite. Till exempel lagrades ett teckenvärde för A som heltalsvärdet 65.
Nytt beteende
Teckenvärden lagras nu som TEXT.
Varför
Att lagra värdena som TEXT är mer naturligt och gör databasen mer kompatibel med andra tekniker.
Åtgärder
Du kan migrera befintliga databaser till det nya formatet genom att köra SQL på följande sätt.
UPDATE MyTable
SET CharColumn = char(CharColumn)
WHERE typeof(CharColumn) = 'integer';
I EF Core kan du också fortsätta att använda det tidigare beteendet genom att konfigurera en värdekonverterare för dessa egenskaper.
modelBuilder
.Entity<MyEntity>()
.Property(e => e.CharProperty)
.HasConversion(
c => (long)c,
i => (char)i);
Microsoft.Data.Sqlite kan också läsa teckenvärden från både INTEGER- och TEXT-kolumner, så vissa scenarier kanske inte kräver någon åtgärd.
Migrerings-ID:t genereras nu med hjälp av den invarianta kulturens kalender
Gammalt beteende
Migrerings-ID:t genererades oavsiktligt med hjälp av den aktuella kulturens kalender.
Nytt beteende
Migrerings-ID:t genereras nu alltid med hjälp av den invarianta kulturens kalender (gregoriansk).
Varför
Migreringsordningen är viktig när du uppdaterar databasen eller löser sammanslagningskonflikter. Med hjälp av den invarianta kalendern undviker du ordningsproblem som kan uppstå när gruppmedlemmar har olika systemkalendrar.
Åtgärder
Den här ändringen påverkar alla som använder en icke-gregoriansk kalender där året är större än den gregorianska kalendern (som den thailändska buddistiska kalendern). Befintliga migrerings-ID:n måste uppdateras så att nya migreringar ordnas efter befintliga migreringar.
Migrerings-ID:t finns i migreringsattributet i migreringsdesignerfilerna.
[DbContext(typeof(MyDbContext))]
-[Migration("25620318122820_MyMigration")]
+[Migration("20190318122820_MyMigration")]
partial class MyMigration
{
Tabellen Migreringshistorik måste också uppdateras.
UPDATE __EFMigrationsHistory
SET MigrationId = CONCAT(LEFT(MigrationId, 4) - 543, SUBSTRING(MigrationId, 4, 150))
UseRowNumberForPaging har tagits bort
Gammalt beteende
Innan EF Core 3.0 kunde UseRowNumberForPaging
användas för att generera SQL för sidindelning som är kompatibel med SQL Server 2008.
Nytt beteende
Från och med EF Core 3.0 genererar EF endast SQL för paginering som endast är kompatibelt med nyare versioner av SQL Server.
Varför
Vi gör den här ändringen eftersom SQL Server 2008 inte längre är en produkt som stöds och det är ett betydande arbete att uppdatera den här funktionen för att arbeta med frågeändringarna som gjorts i EF Core 3.0.
Åtgärder
Vi rekommenderar att du uppdaterar till en nyare version av SQL Server eller använder en högre kompatibilitetsnivå, så att den genererade SQL stöds. Med detta sagt, om du inte kan göra detta kan du kommentera spårningsproblemet med information. Vi kan komma att återkomma till det här beslutet baserat på feedback.
Tilläggsinformation/metadata har tagits bort från IDbContextOptionsExtension
Gammalt beteende
IDbContextOptionsExtension
innehåller metoder för att tillhandahålla metadata om tillägget.
Nytt beteende
Dessa metoder har flyttats till en ny DbContextOptionsExtensionInfo
abstrakt basklass, som returneras från en ny IDbContextOptionsExtension.Info
egenskap.
Varför
I versionerna från 2.0 till 3.0 behövde vi lägga till eller ändra dessa metoder flera gånger. Om du delar upp dem i en ny abstrakt basklass blir det enklare att göra den här typen av ändringar utan att bryta befintliga tillägg.
Åtgärder
Uppdatera tillägg för att följa det nya mönstret.
Exempel finns i många implementeringar av IDbContextOptionsExtension
för olika typer av tillägg i EF Core-källkoden.
LogQueryPossibleExceptionWithAggregateOperator har bytt namn
Förändring
RelationalEventId.LogQueryPossibleExceptionWithAggregateOperator
har bytt namn till RelationalEventId.LogQueryPossibleExceptionWithAggregateOperatorWarning
.
Varför
Justerar namngivningen av den här varningshändelsen med alla andra varningshändelser.
Åtgärder
Använd det nya namnet. (Observera att händelse-ID-numret inte har ändrats.)
Förtydliga API:et för namn på främmande nyckelbegränsningar
Gammalt beteende
Före EF Core 3.0 kallades främmande nyckelns begränsningsnamn helt enkelt för "namn". Till exempel:
var constraintName = myForeignKey.Name;
Nytt beteende
Från och med EF Core 3.0 kallas namn på främmande nyckelvillkor nu för "villkorsnamn". Till exempel:
var constraintName = myForeignKey.ConstraintName;
Varför
Den här ändringen ger konsekvens i namngivning i det här området och klargör även att det här är namnet på villkoret för sekundärnyckeln, och inte kolumnen eller egenskapsnamnet som sekundärnyckeln definieras på.
Åtgärder
Använd det nya namnet.
IRelationalDatabaseCreator.HasTables/HasTablesAsync har blivit offentliga
Gammalt beteende
Före EF Core 3.0 skyddades dessa metoder.
Nytt beteende
Från och med EF Core 3.0 är dessa metoder offentliga.
Varför
Dessa metoder används av EF för att avgöra om en databas skapas men är tom. Detta kan också vara användbart utanför EF när du avgör om migreringar ska tillämpas eller inte.
Minskningar
Ändra tillgängligheten för alla överstyrningar.
Microsoft.EntityFrameworkCore.Design är nu ett DevelopmentDependency-paket
Gammalt beteende
Före EF Core 3.0 var Microsoft.EntityFrameworkCore.Design ett vanligt NuGet-paket vars sammansättning kunde refereras till av projekt som var beroende av det.
Nytt beteende
Från och med EF Core 3.0 är det ett DevelopmentDependency-paket. Det innebär att beroendet inte flödar transitivt till andra projekt och att du inte längre som standard kan referera till dess sammansättning.
Varför
Det här paketet är endast avsett att användas vid designtillfället. Distribuerade program bör inte referera till det. Att göra paketet till ett DevelopmentDependency förstärker den här rekommendationen.
Åtgärder
Om du behöver referera till det här paketet för att åsidosätta EF Cores designtidsbeteende kan du uppdatera PackageReference-objektmetadata i projektet.
<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>
Om paketet refereras transitivt via Microsoft.EntityFrameworkCore.Tools måste du lägga till en explicit PackageReference i paketet för att ändra dess metadata. En sådan explicit referens måste läggas till i alla projekt där typerna från paketet behövs.
SQLitePCL.raw uppdaterad till version 2.0.0
Gammalt beteende
Microsoft.EntityFrameworkCore.Sqlite var tidigare beroende av version 1.1.12 av SQLitePCL.raw.
Nytt beteende
Vi har uppdaterat vårt paket så att det beror på version 2.0.0.
Varför
Version 2.0.0 av SQLitePCL.raw riktar sig mot .NET Standard 2.0. Den var tidigare riktad mot .NET Standard 1.1 som krävde en stor stängning av transitiva paket för att fungera.
Åtgärder
SQLitePCL.raw version 2.0.0 innehåller några icke-bakåtkompatibla ändringar. Mer information finns i utgivningsanteckningar.
NetTopologySuite har uppdaterats till version 2.0.0
Gammalt beteende
De rumsliga paket som tidigare var beroende av version 1.15.1 av NetTopologySuite.
Nytt beteende
Vi har uppdaterat vårt paket så att det är beroende av version 2.0.0.
Varför
Version 2.0.0 av NetTopologySuite syftar till att åtgärda flera användbarhetsproblem som EF Core-användare stöter på.
Åtgärder
NetTopologySuite version 2.0.0 innehåller vissa icke-bakåtkompatibla ändringar. För mer information, se versionsinformation.
Microsoft.Data.SqlClient används i stället för System.Data.SqlClient
Gammalt beteende
Microsoft.EntityFrameworkCore.SqlServer var tidigare beroende av System.Data.SqlClient.
Nytt beteende
Vi har uppdaterat vårt paket så att det är beroende av Microsoft.Data.SqlClient.
Varför
Microsoft.Data.SqlClient är huvuddrivrutinen för dataåtkomst för SQL Server framöver och System.Data.SqlClient är inte längre i fokus för utveckling. Vissa viktiga funktioner, till exempel Always Encrypted, är endast tillgängliga på Microsoft.Data.SqlClient.
Åtgärder
Om koden är direkt beroende av System.Data.SqlClient måste du ändra den så att den refererar till Microsoft.Data.SqlClient i stället. eftersom de två paketen har en mycket hög grad av API-kompatibilitet bör detta bara vara ett enkelt paket och namnområdesändring.
Flera tvetydiga självrefererande relationer måste konfigureras
Gammalt beteende
En entitetstyp med flera självrefererande uni-directional navigeringsegenskaper och matchande FK:er har felaktigt konfigurerats som en enda relation. Till exempel:
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; }
}
Nytt beteende
Det här scenariot identifieras nu i modellbygget och ett undantag genereras som indikerar att modellen är tvetydig.
Varför
Den resulterande modellen var tvetydig och kommer sannolikt vanligtvis att vara fel för det här fallet.
Åtgärder
Använd fullständig konfiguration av relationen. Till exempel:
modelBuilder
.Entity<User>()
.HasOne(e => e.CreatedBy)
.WithMany();
modelBuilder
.Entity<User>()
.HasOne(e => e.UpdatedBy)
.WithMany();
DbFunction.Schema som är null eller tom sträng konfigurerar att det finns i modellens standardschema
Gammalt beteende
En DbFunction som konfigurerats med schemat som en tom sträng behandlades som en inbyggd funktion utan schema. Följande kod mappar till exempel DatePart
CLR-funktion till DATEPART
inbyggd funktion i SqlServer.
[DbFunction("DATEPART", Schema = "")]
public static int? DatePart(string datePartArg, DateTime? date) => throw new Exception();
Nytt beteende
Alla DbFunction-mappningar anses vara mappade till användardefinierade funktioner. Därför skulle ett tomt strängvärde placera funktionen i standardschemat för modellen. Vilket kan vara schemat som är konfigurerat explicit via fluent API modelBuilder.HasDefaultSchema()
, eller dbo
annars.
Varför
Tidigare var schemat tomt på ett sätt att behandla att funktionen är inbyggd, men den logiken gäller endast för SqlServer där inbyggda funktioner inte tillhör något schema.
Åtgärder
Konfigurera DbFunctions översättning manuellt för att mappa den till en inbyggd funktion.
modelBuilder
.HasDbFunction(typeof(MyContext).GetMethod(nameof(MyContext.DatePart)))
.HasTranslation(args => SqlFunctionExpression.Create("DatePart", args, typeof(int?), null));
EF Core 3.0 riktar sig mot .NET Standard 2.1 i stället för .NET Standard 2.0 återställd
EF Core 3.0 riktar sig mot .NET Standard 2.1, vilket är en brytförändring som exkluderar .NET Framework-program. EF Core 3.1 återställde detta och riktar in sig på .NET Standard 2.0 igen.
Frågekörning loggas på felsökningsnivå återställd
Vi har återställt den här ändringen eftersom den nya konfigurationen i EF Core 3.0 tillåter att loggnivån för alla händelser anges av programmet. Om du till exempel vill växla loggning av SQL till Debug
konfigurerar du explicit nivån i OnConfiguring
eller AddDbContext
:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseSqlServer(connectionString)
.ConfigureWarnings(c => c.Log((RelationalEventId.CommandExecuting, LogLevel.Debug)));