Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Anmärkning
ENDAST EF6 – De funktioner, API:er osv. som beskrivs på den här sidan introducerades i Entity Framework 6. Om du använder en tidigare version gäller inte en del av eller all information.
Som standard konfigurerar Code First alla entiteter för att utföra kommandon för att infoga, uppdatera och ta bort med direkt tabellåtkomst. Från och med EF6 kan du konfigurera code first-modellen så att den använder lagrade procedurer för vissa eller alla entiteter i din modell.
Grundläggande entitetsmappning
Du kan välja att använda lagrade procedurer för att infoga, uppdatera och ta bort med hjälp av Fluent API.
modelBuilder
.Entity<Blog>()
.MapToStoredProcedures();
Detta gör att Code First använder vissa konventioner för att skapa den förväntade formen för de lagrade procedurerna i databasen.
- Tre lagrade procedurer med namnet <type_name>_Insert, <type_name>_Update och <type_name>_Delete (till exempel Blog_Insert, Blog_Update och Blog_Delete).
- Parameternamn motsvarar egenskapsnamnen.
Anmärkning
Om du använder HasColumnName() eller attributet Column för att byta namn på kolumnen för en viss egenskap används det här namnet för parametrar i stället för egenskapsnamnet.
- Insättningsproceduren kommer att ha en parameter för varje egenskap, förutom de som har markerats som genererade av databasen (identitetsvärde eller beräknat värde). Den lagrade proceduren ska returnera en resultatuppsättning med en kolumn för varje egenskap genererad av butiken.
- Den lagrade uppdateringsproceduren har en parameter för varje egenskap, förutom de som har markerats med ett butiksgenererat mönster av "Computed". Vissa samtidighetstoken kräver en parameter för det ursprungliga värdet. Mer information finns i avsnittet Samtidighetstoken nedan. Den lagrade proceduren ska returnera en resultatuppsättning med en kolumn för varje beräknad egenskap.
- Den lagrade borttagningsproceduren bör ha en parameter för nyckelvärdet för entiteten (eller flera parametrar om entiteten har en sammansatt nyckel). Dessutom bör borttagningsproceduren också ha parametrar för oberoende association främmande nycklar i måltabellen (relationer som inte har motsvarande främmande nyckelegenskaper deklarerade i entiteten). Vissa samtidighetstoken kräver en parameter för det ursprungliga värdet. Mer information finns i avsnittet Samtidighetstoken nedan.
Använd följande klass som exempel:
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
}
Standardlagringsprocedurerna är:
CREATE PROCEDURE [dbo].[Blog_Insert]
@Name nvarchar(max),
@Url nvarchar(max)
AS
BEGIN
INSERT INTO [dbo].[Blogs] ([Name], [Url])
VALUES (@Name, @Url)
SELECT SCOPE_IDENTITY() AS BlogId
END
CREATE PROCEDURE [dbo].[Blog_Update]
@BlogId int,
@Name nvarchar(max),
@Url nvarchar(max)
AS
UPDATE [dbo].[Blogs]
SET [Name] = @Name, [Url] = @Url
WHERE BlogId = @BlogId;
CREATE PROCEDURE [dbo].[Blog_Delete]
@BlogId int
AS
DELETE FROM [dbo].[Blogs]
WHERE BlogId = @BlogId
Åsidosätta standardvärdena
Du kan åsidosätta en del av eller allt som har konfigurerats som standard.
Du kan ändra namnet på en eller flera lagrade procedurer. Det här exemplet byter endast namn på den lagrade uppdateringsproceduren.
modelBuilder
.Entity<Blog>()
.MapToStoredProcedures(s =>
s.Update(u => u.HasName("modify_blog")));
Det här exemplet byter namn på alla tre lagrade procedurer.
modelBuilder
.Entity<Blog>()
.MapToStoredProcedures(s =>
s.Update(u => u.HasName("modify_blog"))
.Delete(d => d.HasName("delete_blog"))
.Insert(i => i.HasName("insert_blog")));
I de här exemplen är anropen sammanlänkade, men du kan också använda lambda-blocksyntax.
modelBuilder
.Entity<Blog>()
.MapToStoredProcedures(s =>
{
s.Update(u => u.HasName("modify_blog"));
s.Delete(d => d.HasName("delete_blog"));
s.Insert(i => i.HasName("insert_blog"));
});
Det här exemplet byter namn på parametern för egenskapen BlogId i den lagrade uppdateringsproceduren.
modelBuilder
.Entity<Blog>()
.MapToStoredProcedures(s =>
s.Update(u => u.Parameter(b => b.BlogId, "blog_id")));
De här anropen är alla länkbara och sammansättningsbara. Här är ett exempel som byter namn på alla tre lagrade procedurer och deras parametrar.
modelBuilder
.Entity<Blog>()
.MapToStoredProcedures(s =>
s.Update(u => u.HasName("modify_blog")
.Parameter(b => b.BlogId, "blog_id")
.Parameter(b => b.Name, "blog_name")
.Parameter(b => b.Url, "blog_url"))
.Delete(d => d.HasName("delete_blog")
.Parameter(b => b.BlogId, "blog_id"))
.Insert(i => i.HasName("insert_blog")
.Parameter(b => b.Name, "blog_name")
.Parameter(b => b.Url, "blog_url")));
Du kan också ändra namnet på kolumnerna i resultatuppsättningen som innehåller databasgenererade värden.
modelBuilder
.Entity<Blog>()
.MapToStoredProcedures(s =>
s.Insert(i => i.Result(b => b.BlogId, "generated_blog_identity")));
CREATE PROCEDURE [dbo].[Blog_Insert]
@Name nvarchar(max),
@Url nvarchar(max)
AS
BEGIN
INSERT INTO [dbo].[Blogs] ([Name], [Url])
VALUES (@Name, @Url)
SELECT SCOPE_IDENTITY() AS generated_blog_id
END
Relationer utan främmande nyckel i klass (oberoende associationer)
När en sekundärnyckelegenskap ingår i klassdefinitionen kan motsvarande parameter byta namn på samma sätt som andra egenskaper. När en relation finns utan en sekundärnyckelegenskap i klassen är standardparameternamnet navigation_property_name<_>primary_key_name<.>
Följande klassdefinitioner skulle till exempel resultera i att en Blog_BlogId parameter förväntas i de lagrade procedurerna för att infoga och uppdatera inlägg.
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public Blog Blog { get; set; }
}
Åsidosätta standardvärdena
Du kan ändra parametrar för sekundärnycklar som inte ingår i klassen genom att ange sökvägen till primärnyckelegenskapen till parametermetoden.
modelBuilder
.Entity<Post>()
.MapToStoredProcedures(s =>
s.Insert(i => i.Parameter(p => p.Blog.BlogId, "blog_id")));
Om du inte har någon navigeringsegenskap för den beroende entiteten (dvs. ingen Post.Blog egenskap) kan du använda metoden Association för att identifiera den andra änden av relationen och sedan konfigurera parametrarna som motsvarar var och en av nyckelegenskaperna.
modelBuilder
.Entity<Post>()
.MapToStoredProcedures(s =>
s.Insert(i => i.Navigation<Blog>(
b => b.Posts,
c => c.Parameter(b => b.BlogId, "blog_id"))));
Samtidighetstoken
Lagrade procedurer för uppdatering och borttagning kan också behöva hantera samtidighet:
- Om entiteten innehåller samtidighetstoken kan den lagrade proceduren eventuellt ha en utdataparameter som returnerar antalet rader som har uppdaterats/tagits bort (rader som påverkas). En sådan parameter måste konfigureras med metoden RowsAffectedParameter.
Som standard använder EF returvärdet från ExecuteNonQuery för att avgöra hur många rader som påverkades. Det är användbart att ange en utdataparameter för påverkade rader om du utför någon logik i din sproc som skulle resultera i att returvärdet för ExecuteNonQuery blir felaktigt (från EF:s perspektiv) i slutet av körningen. - För varje samtidighetstoken finns det en parameter med namnet <property_name>_Original (till exempel Timestamp_Original ). Det ursprungliga värdet av denna egenskap kommer att överföras – värdet när det hämtas från databasen.
- Samtidighetstoken som beräknas av databasen – till exempel tidsstämplar – har bara en ursprunglig värdeparameter.
- Icke-beräknade egenskaper som anges som samtidighetstoken har också en parameter för det nya värdet i uppdateringsproceduren. Detta använder namngivningskonventionerna som redan diskuterats för nya värden. Ett exempel på en sådan token skulle vara att använda en bloggs URL som en samtidighetstoken, det nya värdet krävs eftersom detta kan uppdateras till ett nytt värde av din kod (till skillnad från en tidsstämpeltoken som endast uppdateras av databasen).
Det här är en exempelklass och en uppdatering av lagrad procedur med en tidsstämpel för samtidighetstoken.
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
[Timestamp]
public byte[] Timestamp { get; set; }
}
CREATE PROCEDURE [dbo].[Blog_Update]
@BlogId int,
@Name nvarchar(max),
@Url nvarchar(max),
@Timestamp_Original rowversion
AS
UPDATE [dbo].[Blogs]
SET [Name] = @Name, [Url] = @Url
WHERE BlogId = @BlogId AND [Timestamp] = @Timestamp_Original
Här är en exempelklass och uppdatering av lagrad procedur med icke-beräknad samtidighetstoken.
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
[ConcurrencyCheck]
public string Url { get; set; }
}
CREATE PROCEDURE [dbo].[Blog_Update]
@BlogId int,
@Name nvarchar(max),
@Url nvarchar(max),
@Url_Original nvarchar(max),
AS
UPDATE [dbo].[Blogs]
SET [Name] = @Name, [Url] = @Url
WHERE BlogId = @BlogId AND [Url] = @Url_Original
Åsidosätta standardvärdena
Du kan också introducera en rad som påverkas av parametern.
modelBuilder
.Entity<Blog>()
.MapToStoredProcedures(s =>
s.Update(u => u.RowsAffectedParameter("rows_affected")));
För databasberäknade samtidighetstoken – där endast det ursprungliga värdet skickas – kan du bara använda standardparameterns namnbytesmekanism för att byta namn på parametern för det ursprungliga värdet.
modelBuilder
.Entity<Blog>()
.MapToStoredProcedures(s =>
s.Update(u => u.Parameter(b => b.Timestamp, "blog_timestamp")));
För icke-beräknade samtidighetstoken – där både det ursprungliga och det nya värdet skickas – kan du använda en överlagring av Parameter som gör att du kan specificera ett namn för varje parameter.
modelBuilder
.Entity<Blog>()
.MapToStoredProcedures(s => s.Update(u => u.Parameter(b => b.Url, "blog_url", "blog_original_url")));
Många till många relationer
Vi använder följande klasser som exempel i det här avsnittet.
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public List<Tag> Tags { get; set; }
}
public class Tag
{
public int TagId { get; set; }
public string TagName { get; set; }
public List<Post> Posts { get; set; }
}
Många till många relationer kan mappas till lagrade procedurer med följande syntax.
modelBuilder
.Entity<Post>()
.HasMany(p => p.Tags)
.WithMany(t => t.Posts)
.MapToStoredProcedures();
Om ingen annan konfiguration anges används följande lagrade procedurform som standard.
- Två lagrade procedurer med namnet <type_one><type_two>_Insert och <type_one><type_two>_Delete (till exempel PostTag_Insert och PostTag_Delete).
- Parametrarna är nyckelvärdena för varje typ. Namnet på varje parameter som <type_name>_<property_name> (till exempel Post_PostId och Tag_TagId).
Här är exempel på infoga och uppdatera lagrade procedurer.
CREATE PROCEDURE [dbo].[PostTag_Insert]
@Post_PostId int,
@Tag_TagId int
AS
INSERT INTO [dbo].[Post_Tags] (Post_PostId, Tag_TagId)
VALUES (@Post_PostId, @Tag_TagId)
CREATE PROCEDURE [dbo].[PostTag_Delete]
@Post_PostId int,
@Tag_TagId int
AS
DELETE FROM [dbo].[Post_Tags]
WHERE Post_PostId = @Post_PostId AND Tag_TagId = @Tag_TagId
Åsidosätta standardvärdena
Proceduren och parameternamnen kan konfigureras på ett liknande sätt som entitets lagrade procedurer.
modelBuilder
.Entity<Post>()
.HasMany(p => p.Tags)
.WithMany(t => t.Posts)
.MapToStoredProcedures(s =>
s.Insert(i => i.HasName("add_post_tag")
.LeftKeyParameter(p => p.PostId, "post_id")
.RightKeyParameter(t => t.TagId, "tag_id"))
.Delete(d => d.HasName("remove_post_tag")
.LeftKeyParameter(p => p.PostId, "post_id")
.RightKeyParameter(t => t.TagId, "tag_id")));