EF 4 + CTP 5 = CodeFirst : Mapping II
En la anterior entrada sobre mapping, exploramos distintas posiblidades acerca del mapeo con herencia dentro de esta última CTP. A lo largo de la siguiente entrada veremos dos nuevos casos, Entity Spliting y el uso de enumerados, algo que suele ser una pregunta desgraciadamente habitual.
Con el fin de mostrar un ejemplo de Entity Splitting, es decir, una entidad que se mapea a dos tablas, partiremos del siguiente ejemplo de entidad:
public class Customer
{
public int CustomerId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
public string Country { get; set; }
}
El objetivo, es hacer que esta entidad se mapee con dos tablas (una join de las mismas repesenta cada entidad ) llamadas Customers CustomersAddresses. Para ello, dentro de nuestro espacio de mapeo en Code First, este escenario no se puede hacer mediante anotaciones, podemos escribir las siguientes lineas.
public class StoreContext
:DbContext
{
public IDbSet<Customer> Customers { get; set; }
protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
{
modelBuilder.Entity<Customer>()
.Map(mc
=>
{
mc.Properties(c => new { c.CustomerId, c.FirstName, c.LastName });
mc.ToTable("Customers");
})
.Map(mc
=>
{
mc.Properties(c => new { c.CustomerId, c.ZipCode, c.Country, c.City });
mc.ToTable("CustomersAddress");
});
}
}
Si probamos este código, o bien revisamos el diagrama de las tablas generadas, nos prodremos dar cuenta como por defecto las claves generadas para estas dos tablas son de tipo identity, y por lo tanto, no podremos garantizar las uniones e inserciones de los mismos. Para que este escenario funcione correctamente tendremos que eliminar este patron de generación para las claves. Para ello, podemos utilizar el atributo DatabaseGeneration o bien hacerlo por código.
public class StoreContext
:DbContext
{
public IDbSet<Customer> Customers { get; set; }
protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
{
modelBuilder.Entity<Customer>()
.Property(c => c.CustomerId)
.HasDatabaseGenerationOption(DatabaseGenerationOption.None);
modelBuilder.Entity<Customer>()
.Map(mc
=>
{
mc.Properties(c => new { c.CustomerId, c.FirstName, c.LastName });
mc.ToTable("Customers");
})
.Map(mc
=>
{
mc.Properties(c => new { c.CustomerId, c.ZipCode, c.Country, c.City });
mc.ToTable("CustomersAddress");
});
}
}
Tal y como comentamos al principio de esta entrada terminarmos hablando del uso de los malditos enumerados dentro de una entidad. Aunque en realidad, Code First no introduce nada realmente nuevo al respecto. Si con nuestras entidades POCO/STE utilizábamos clases parciales para definir una propiedad con un enumerado, internamente manejaba el valor de una columna, en Code First el truco es idéntico, con la salvedad que no necesitamso una clase parcial porque podemos ignorar el mapping de cualquier propiedad ( con una anotación o bien mediante código en el model builder).
Supongamos que tenemos una entidad Order de la siguiente forma:
public class Order
{
public int OrderId { get; set; }
public int OrderPriorityValue { get; set; }
public decimal TotalOrder { get; set; }
}
Si en esta propiedad, quisiéramos incluir un enumerado para marcar los tipos de prioridad del pedido, podríamos modificarla como sigue:
public class Order
{
public int OrderId { get; set; }
public int OrderPriorityValue { get; set; }
public decimal TotalOrder { get; set; }
public OrderPriority Priority
{
get
{
return (OrderPriority)OrderPriorityValue;
}
}
}
public enum OrderPriority
{
None=0,
Low = 1,
High = 2
}
Lógicamente, Priority no debería ser un elemento a mapear, no sabríamos como, por lo tanto, tenemos que indicarle de alguna manera que cuando se realize el mapping de esta entidades este elemento sea ignorado. Para ello, podríamos hacerlo de las siguientes formas:
1º Usando el atributo NotMapped
public class Order
{
public int OrderId { get; set; }
public int OrderPriorityValue { get; set; }
public decimal TotalOrder { get; set; }
[NotMapped()]
public OrderPriority Priority
{
get
{
return (OrderPriority)OrderPriorityValue;
}
}
}
2º En la configuración de nuestro model builder
public class StoreContext
:DbContext
{
public IDbSet<Order> Orders { get; set; }
protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>().Ignore(o => o.Priority);
}
}
Bueno, hasta aquí esta entrada, la verdad es que ahora mismo no se si habrá tercera parte de mapping, imagino que si pero………
Saludos
Unai