Sdílet prostřednictvím


První vložení, aktualizace a odstranění uložených procedur kódu

Poznámka

Pouze EF6 a novější – Funkce, rozhraní API atd. popsané na této stránce byly představeny v Entity Framework 6. Pokud používáte starší verzi, některé nebo všechny informace nemusí být platné.

Ve výchozím nastavení code First nakonfiguruje všechny entity tak, aby prováděly příkazy pro vložení, aktualizaci a odstranění pomocí přímého přístupu k tabulce. Počínaje ef6 můžete nakonfigurovat model Code First tak, aby používal uložené procedury pro některé nebo všechny entity v modelu.

Základní mapování entit

Pomocí rozhraní Fluent API se můžete rozhodnout používat uložené procedury pro vložení, aktualizaci a odstranění.

modelBuilder
  .Entity<Blog>()
  .MapToStoredProcedures();

Tím způsobíte, že Code First použije některé konvence k sestavení očekávaného tvaru uložených procedur v databázi.

  • Tři uložené procedury s názvem <type_name>_Insert,< type_name>_Update a <type_name>_Delete (například Blog_Insert, Blog_Update a Blog_Delete).
  • Názvy parametrů odpovídají názvům vlastností.

    Poznámka

    Pokud k přejmenování sloupce pro danou vlastnost použijete HasColumnName() nebo atribut Column, použije se tento název pro parametry místo názvu vlastnosti.

  • Uložená procedura vložení bude mít parametr pro každou vlastnost, s výjimkou těch, které jsou označené jako vygenerované úložiště (identita nebo vypočítaná). Uložená procedura by měla vrátit sadu výsledků se sloupcem pro každou vygenerovanou vlastnost úložiště.
  • Uložená procedura aktualizace bude mít parametr pro každou vlastnost, s výjimkou těch, které jsou označené vzorem vygenerovaným úložištěm "Computed". Některé tokeny souběžnosti vyžadují parametr pro původní hodnotu. Podrobnosti najdete v části Concurrency Tokens níže. Uložená procedura by měla vrátit sadu výsledků se sloupcem pro každou vypočítanou vlastnost.
  • Uložená procedura pro odstranění by měla mít parametr pro hodnotu klíče entity (nebo více parametrů, pokud má entita složený klíč). Kromě toho by procedura odstranění měla mít také parametry pro všechny nezávislé asociační cizí klíče v cílové tabulce (relace, které nemají odpovídající vlastnosti cizího klíče deklarované v entitě). Některé tokeny souběžnosti vyžadují parametr pro původní hodnotu. Podrobnosti najdete v části Concurrency Tokens níže.

Jako příklad použijte následující třídu:

public class Blog  
{  
  public int BlogId { get; set; }  
  public string Name { get; set; }  
  public string Url { get; set; }  
}

Výchozí uložené procedury:

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

Přepsání výchozích hodnot

Můžete přepsat část nebo vše, co bylo ve výchozím nastavení nakonfigurováno.

Název jedné nebo více uložených procedur můžete změnit. Tento příklad přejmenuje pouze uloženou proceduru aktualizace.

modelBuilder  
  .Entity<Blog>()  
  .MapToStoredProcedures(s =>  
    s.Update(u => u.HasName("modify_blog")));

Tento příklad přejmenuje všechny tři uložené procedury.

modelBuilder  
  .Entity<Blog>()  
  .MapToStoredProcedures(s =>  
    s.Update(u => u.HasName("modify_blog"))  
     .Delete(d => d.HasName("delete_blog"))  
     .Insert(i => i.HasName("insert_blog")));

V těchto příkladech jsou volání zřetězený dohromady, ale můžete také použít syntaxi bloku lambda.

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"));  
    });

Tento příklad přejmenuje parametr pro vlastnost BlogId u aktualizační uložené procedury.

modelBuilder  
  .Entity<Blog>()  
  .MapToStoredProcedures(s =>  
    s.Update(u => u.Parameter(b => b.BlogId, "blog_id")));

Tato volání jsou všechna zřetězená a kompozovatelná. Tady je příklad, který přejmenuje všechny tři uložené procedury a jejich parametry.

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")));

Můžete také změnit název sloupců v sadě výsledků obsahující hodnoty generované databází.

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

Relace bez cizího klíče ve třídě (nezávislá přidružení)

Pokud je vlastnost cizího klíče zahrnuta v definici třídy, lze odpovídající parametr přejmenovat stejným způsobem jako jakákoli jiná vlastnost. Pokud relace existuje bez vlastnosti cizího klíče ve třídě, výchozí název parametru je <navigation_property_name>_<primary_key_name>.

Například následující definice tříd by měly vést k očekávanému Blog_BlogId parametru v uložených procedurách pro vložení a aktualizaci příspěvků.

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; }  
}

Přepsání výchozích hodnot

Parametry cizích klíčů, které nejsou součástí třídy, můžete změnit zadáním cesty k vlastnosti primárního klíče metodě Parameter.

modelBuilder
  .Entity<Post>()  
  .MapToStoredProcedures(s =>  
    s.Insert(i => i.Parameter(p => p.Blog.BlogId, "blog_id")));

Pokud nemáte navigační vlastnost závislé entity (tj. žádná Post.Blog vlastnost), můžete pomocí metody Association identifikovat druhý konec relace a pak nakonfigurovat parametry, které odpovídají jednotlivým klíčovým vlastnostem.

modelBuilder
  .Entity<Post>()  
  .MapToStoredProcedures(s =>  
    s.Insert(i => i.Navigation<Blog>(  
      b => b.Posts,  
      c => c.Parameter(b => b.BlogId, "blog_id"))));

Tokeny souběžnosti

Aktualizace a odstranění uložených procedur může také vyžadovat souběžnost:

  • Pokud entita obsahuje tokeny souběžnosti, může uložená procedura volitelně obsahovat výstupní parametr, který vrátí počet aktualizovaných nebo odstraněných řádků (ovlivněných řádků). Takový parametr musí být nakonfigurován pomocí RowsAffectedParameter metoda.
    Ve výchozím nastavení ef používá vrácenou hodnotu z ExecuteNonQuery k určení počtu ovlivněných řádků. Zadání výstupního parametru ovlivněného řádky je užitečné, pokud na konci provádění provedete jakoukoli logiku, která by měla vést k nesprávné hodnotě ExecuteNonQuery (z pohledu EF).
  • Pro každý token souběžnosti bude parametr s názvem <property_name>_Original (například Timestamp_Original). Tato hodnota se předá původní hodnota této vlastnosti – hodnota při dotazování z databáze.
    • Tokeny souběžnosti, které databáze vypočítá – například časové razítko – budou mít pouze původní parametr hodnoty.
    • Nepočítání vlastnosti, které jsou nastaveny jako tokeny souběžnosti, budou mít také parametr pro novou hodnotu v aktualizačním postupu. To používá konvence vytváření názvů, které jsou již popsány pro nové hodnoty. Příkladem takového tokenu by bylo použití adresy URL blogu jako token souběžnosti, nová hodnota se vyžaduje, protože ji může váš kód aktualizovat na novou hodnotu (na rozdíl od tokenu časového razítka, který je aktualizován pouze databází).

Toto je příklad třídy a aktualizujte uloženou proceduru pomocí tokenu souběžnosti časového razítka.

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

Tady je příklad třídy a aktualizace uložené procedury s využitím nevýpočtu tokenu souběžnosti.

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

Přepsání výchozích hodnot

Volitelně můžete zavést parametr ovlivněný řádky.

modelBuilder  
  .Entity<Blog>()  
  .MapToStoredProcedures(s =>  
    s.Update(u => u.RowsAffectedParameter("rows_affected")));

U tokenů souběžnosti vypočítaných v databázi , kde se předává pouze původní hodnota, stačí použít mechanismus přejmenování standardního parametru k přejmenování parametru pro původní hodnotu.

modelBuilder  
  .Entity<Blog>()  
  .MapToStoredProcedures(s =>  
    s.Update(u => u.Parameter(b => b.Timestamp, "blog_timestamp")));

Pro nepočítáné tokeny souběžnosti – kde se předává původní i nová hodnota – můžete použít přetížení parametru, který umožňuje zadat název pro každý parametr.

modelBuilder
 .Entity<Blog>()
 .MapToStoredProcedures(s => s.Update(u => u.Parameter(b => b.Url, "blog_url", "blog_original_url")));

Relace M:N

Jako příklad v této části použijeme následující třídy.

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; }  
}

Mnoho až mnoho relací lze mapovat na uložené procedury s následující syntaxí.

modelBuilder  
  .Entity<Post>()  
  .HasMany(p => p.Tags)  
  .WithMany(t => t.Posts)  
  .MapToStoredProcedures();

Pokud není zadána žádná jiná konfigurace, použije se ve výchozím nastavení následující obrazec uložené procedury.

  • Dvě uložené procedury s názvem <type_one type_two><>_Insert a< type_one type_two><>_Delete (například PostTag_Insert a PostTag_Delete).
  • Parametry budou hodnotou klíče pro každý typ. Název každého parametru, který je <type_name>_<property_name> (například Post_PostId a Tag_TagId).

Tady je příklad vložení a aktualizace uložených procedur.

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

Přepsání výchozích hodnot

Názvy procedur a parametrů lze nakonfigurovat podobným způsobem jako uložené procedury entity.

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")));