Crear un índice vía Fluent API ha resultado ser una tarea nada intuitiva y más difícil de lo esperado. Es por ello que lo voy a dejar por escrito y así, siguientes veces, no tendré que navegar por mi código para buscar la chuleta de cómo hacerlo, porque en mi opinión es un código irrecordable y que no nunca logro descubrir a golpe de Intellisense.
Partiendo de una entidad muy sencilla como la siguiente:
class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public string Country { get; set; }
public DateTime CreatedDate { get; set; }
}
Hacer un índice único por el campo Name sería asi:
modelBuilder
.Entity<Customer>()
.Property(t => t.Name)
.HasMaxLength(250)
.HasColumnAnnotation(IndexAnnotation.AnnotationName,
new IndexAnnotation(new IndexAttribute() { IsUnique = true }));
Si esto ya parece un código algo enrevesado, crear un índice por varios campos es aun mas sorpredente porque es imprescindible dar un nombre al índice y una posición a cada campo:
var customer = modelBuilder.Entity<Customer>();
const string indexName = "IX_Customers";
customer
.Property(t => t.Name)
.HasMaxLength(250)
.HasColumnAnnotation(
IndexAnnotation.AnnotationName,
new IndexAnnotation(
new IndexAttribute(indexName, 1)
{
IsUnique = true
}));
customer
.Property(t => t.Country)
.HasMaxLength(250)
.HasColumnAnnotation(
IndexAnnotation.AnnotationName,
new IndexAnnotation(
new IndexAttribute(indexName, 2)
{
IsUnique = true
}));
El poner un tamaño a las propiedades de tipo string es porque si no se mapearán a nvarchar(max) y la creación del índice fallará en Sql Server.
Originalmente el post llevaba hasta aquí, pero el bueno de @gulnor me incito me incitó de mala manera a dar una solución y no sólo exponer un problema, y claro, después de leer su reciente y reflexivo post Código abierto, ecosistema cerrado, me he sentido un poco culpable y no he tenido otra que corresponder con una posible solución para que que así no se diga que no contribuyo (o al menos lo intento) :)
La idea es poder crear un índice sin todo el ruido que genera el código anterior, algo asi:
modelBuilder.Entity<Customer>().Index(p => p.Name, true, "IX_Customers", 1);
modelBuilder.Entity<Customer>().Index(p => p.Country, true, "IX_Customers", 2);
modelBuilder.Entity<Customer>().Index(p => p.CreatedDate);
El código con los métodos extensores es el siguiente (en el que no me gusta el nombre del parámetro genérico T2 y además reconozco abusar de la indentación, pero es por un buen motivo, para facilitar la lectura en el blog):
static class ModelBuilderExtensions
{
private static void CreateIndex(
PrimitivePropertyConfiguration property,
bool isUnique = false,
string name = null,
int position = 1)
{
var indexAttribute = new IndexAttribute();
if (!string.IsNullOrWhiteSpace(name))
{
indexAttribute = new IndexAttribute(
name,
position <= 0 ? 1 : position);
}
indexAttribute.IsUnique = isUnique;
property.HasColumnAnnotation(
IndexAnnotation.AnnotationName,
new IndexAnnotation(indexAttribute));
}
public static void Index<T, T2>(
this EntityTypeConfiguration<T> entity,
Expression<Func<T, T2>> propertyExpression,
bool isUnique = false,
string name = null,
int position = 1) where T : class where T2 : struct
{
var property = entity.Property(propertyExpression);
CreateIndex(property, isUnique, name, position);
}
public static void Index<T, T2>(
this EntityTypeConfiguration<T> entity,
Expression<Func<T, T2?>> propertyExpression,
bool isUnique = false,
string name = null,
int position = 1) where T : class where T2 : struct
{
var property = entity.Property(propertyExpression);
CreateIndex(property, isUnique, name, position);
}
public static void Index<T>(
this EntityTypeConfiguration<T> entity,
Expression<Func<T, string>> propertyExpression,
bool isUnique = false,
string name = null,
int position = 1) where T : class
{
var property = entity.Property(propertyExpression);
CreateIndex(property, isUnique, name, position);
}
}
Ahora sí, post cerrado!
Un saludo!
No hay comentarios:
Publicar un comentario