Entity Framework y los indices únicos.

Ya me imaginaba yo que después de ver con Profiler las sentencias que genera  con algún que otro problema nos íbamos a encontrar.

Vamos a plantearnos el siguiente problema, tenemos una entidad países con las siguientes propiedades.

   1: public class Pais

   2: {

   3:     public int Id { get; set; }

   4:     public string Nombre { get; set; }

   5:     public string Codigo { get; set; }

   6: }

Utilizando EF 4.3 y Migrations vamos a generar la tabla en la bb.dd y uno de los requerimientos es que “Codigo” sea único, si queréis ampliar temas de Migrations podéis visitar el blog de Javier Torrecilla. Yo os muestro el código tal y como lo he generado para crear la tabla.

   1: namespace WindowsFormsApplication1.Migrations

   2: {

   3:     using System.Data.Entity.Migrations;

   4:     

   5:     public partial class Paises : DbMigration

   6:     {

   7:         public override void Up()

   8:         {

   9:             CreateTable(

  10:                 "Pais",

  11:                 c => new

  12:                     {

  13:                         Id = c.Int(nullable: false, identity: true),

  14:                         Nombre = c.String(nullable:false,maxLength:50,unicode:false),

  15:                         Codigo = c.String(nullable: false, maxLength: 3, unicode: false),

  16:                     })

  17:                 .PrimaryKey(t => t.Id);

  18:  

  19:             CreateIndex("Pais", "Codigo", unique: true);

  20:             

  21:         }

  22:         

  23:         public override void Down()

  24:         {

  25:             DropTable("Pais");

  26:            

  27:         }

  28:     }

  29: }

Ahora vamos con nuestros requerimientos, en la tabla tenemos dos paises “España” y “Francia” que los podemos agregar con las siguientes instrucciones.

   1: using (Context ct = new Context())

   2: {

   3:     ct.Paises.Add(new Pais(){Nombre="España",Codigo="34"});

   4:     ct.Paises.Add(new Pais() { Nombre = "Francia", Codigo = "33" });

   5:     ct.SaveChanges();

   6: }

Y ahora nos dicen que lea la tabla Países y que cambie el código de “España a 33” y elimine “Francia” y de paso que inserte “China con código 35”.

Bueno pues sencillo

   1: using (Context ct = new Context())

   2: {

   3:     var paises = ct.Paises.AsEnumerable();

   4:     foreach (var pais in paises)

   5:     {

   6:         if (pais.Nombre == "Francia")

   7:         {

   8:             ct.Paises.Remove(pais);

   9:         }

  10:         else if (pais.Nombre == "España")

  11:         {

  12:             pais.Codigo = "33";

  13:         }

  14:     }

  15:     ct.Paises.Add(new Pais() { Nombre = "La China", Codigo = "35" });

  16:     ct.SaveChanges();

  17: }

Que ocurre que cuando ejecutamos nos encontramos con una sorprendente exception del tipo DbUpdateException, pero si miramos su InnerExceptión nos encontramos una SqlExceptión que nos dice lo siguiente.

“Cannot insert duplicate key row in object ‘dbo.Pais’ with unique index ‘IX_Codigo’.”

Claro que ocurre que Entity Framework ejecuta primero “Update,Delete,Insert”, con lo cual yo siempre pensé que era “Delete,Update,Insert”, pero aún así en determinados escenarios nos podría ocasionar problemas.

Conclusiones.

Os voy a ser sincero, es un problema complicado de resolver, pero como dicen poder se puede, la verdad que no lo he probado con Merge, pero yo hasta ahora lo hacía de la siguiente forma.

Delete Tabla From, Update Tabla From, Insert Into Select y la verdad que os confieso que dormía bastante tranquilo, cosa que a partir de este momento no lo voy a hacer tanto.

Lanzo una pregunta ¿Os gustaría en linq que se pudieses ejecutar este tipo de sentencías?

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *