Convenciones de Code First

Code First permite describir un modelo mediante clases .NET de C# o Visual Basic. La forma básica del modelo se detecta mediante convenciones. Las convenciones son conjuntos de reglas que se utilizan para configurar automáticamente un modelo conceptual basado en definiciones de clase cuando se trabaja con Code First. Las convenciones se definen en el espacio de nombres System.Data.Entity.ModelConfiguration.Conventions.

Es posible configurar aún más el modelo mediante anotaciones de datos o la API fluida. La prioridad se da a la configuración a través de la API fluida, seguida de anotaciones de datos y, a continuación, convenciones. Para obtener más información, consulte Anotaciones de datos, API fluida: relaciones, API fluida: tipos y propiedades y API fluida con VB.NET.

Hay disponible una lista detallada de convenciones de Code First en la documentación de la API. En este tema se proporciona información general sobre las convenciones usadas por Code First.

Detección de tipos

Al usar el desarrollo de Code First, normalmente se comienza por escribir clases de .NET Framework que definen el modelo conceptual (dominio). Además de definir las clases, también es necesario permitir que DbContext sepa qué tipos se desean incluir en el modelo. Para ello, defina una clase de contexto que derive de DbContext y exponga las propiedades de DbSet para los tipos que desee que formen parte del modelo. Code First incluirá estos tipos y extraerá los tipos a los que se hace referencia también, incluso si los tipos a los que se hace referencia se definieran en un ensamblado diferente.

Si los tipos participasen en una jerarquía de herencia, bastará con definir una propiedad de DbSet para la clase base y los tipos derivados se incluirán automáticamente, siempre que estén en el mismo ensamblado que la clase base.

En el ejemplo siguiente, solo hay una propiedad DbSet definida en la clase EntidadesEscolares (Departamentos). Code First usa esta propiedad para detectar y extraer cualquier tipo al que se haga referencia.

public class SchoolEntities : DbContext
{
    public DbSet<Department> Departments { get; set; }
}

public class Department
{
    // Primary key
    public int DepartmentID { get; set; }
    public string Name { get; set; }

    // Navigation property
    public virtual ICollection<Course> Courses { get; set; }
}

public class Course
{
    // Primary key
    public int CourseID { get; set; }

    public string Title { get; set; }
    public int Credits { get; set; }

    // Foreign key
    public int DepartmentID { get; set; }

    // Navigation properties
    public virtual Department Department { get; set; }
}

public partial class OnlineCourse : Course
{
    public string URL { get; set; }
}

public partial class OnsiteCourse : Course
{
    public string Location { get; set; }
    public string Days { get; set; }
    public System.DateTime Time { get; set; }
}

Si desea excluir un tipo del modelo, use el atributo NotMapped o la API fluida DbModelBuilder.Ignore.

modelBuilder.Ignore<Department>();

Convención de clave principal

Code First deduce que una propiedad es una clave principal si una propiedad de una clase se denomina “ID” (no distingue mayúsculas de minúsculas) o el nombre de clase seguido de "ID". Si el tipo de la propiedad de clave principal fuera numérico o GUID, se configurará como una columna de identidad.

public class Department
{
    // Primary key
    public int DepartmentID { get; set; }

    . . .  

}

Convención de la relación

En Entity Framework, las propiedades de navegación proporcionan una manera de navegar por una relación entre dos tipos de entidad. Cada objeto puede tener una propiedad de navegación para cada relación en la que participa. Las propiedades de navegación permiten navegar y administrar las relaciones en ambas direcciones, devolviendo un objeto de referencia (si la multiplicidad es de uno o cero o uno) o bien una colección (si la multiplicidad es de varios). Code First deduce las relaciones en función de las propiedades de navegación definidas en los tipos.

Además de las propiedades de navegación, se recomienda incluir propiedades de clave externa en los tipos que representan objetos dependientes. Cualquier propiedad con el mismo tipo de datos que la propiedad principal de clave principal y con un nombre que siga a uno de los siguientes formatos representará una clave externa para la relación: "<nombre de propiedad de navegación><nombre de propiedad principal de clave principal>", "<nombre de clase principal><nombre de propiedad de clave principal>" o "<nombre de propiedad principal de clave principal>". Si se encontrasen varias coincidencias, la prioridad se dará en el orden indicado anteriormente. La detección de claves externas no distingue mayúsculas de minúsculas. Cuando se detecta una propiedad de clave externa, Code First deduce la multiplicidad de la relación en función de la nulabilidad de la clave externa. Si la propiedad admitiera valores NULL, la relación se registrará como opcional. De lo contrario, la relación se registrará según fuera necesario.

Si una clave externa en la entidad dependiente no admitiera valores NULL, entonces Code First establecerá la eliminación en cascada en la relación. Si una clave ajena en la entidad dependiente no admitiera valores NULL, Code First no establecerá la eliminación en cascada en la relación y, cuando se elimine la entidad principal, la clave ajena se establecerá como nula. El comportamiento de eliminación en cascada y multiplicidad detectado por convención se puede invalidar mediante la API fluida.

En el ejemplo siguiente, se usan las propiedades de navegación y una clave externa para definir la relación entre las clases Department y Course.

public class Department
{
    // Primary key
    public int DepartmentID { get; set; }
    public string Name { get; set; }

    // Navigation property
    public virtual ICollection<Course> Courses { get; set; }
}

public class Course
{
    // Primary key
    public int CourseID { get; set; }

    public string Title { get; set; }
    public int Credits { get; set; }

    // Foreign key
    public int DepartmentID { get; set; }

    // Navigation properties
    public virtual Department Department { get; set; }
}

Nota:

Si tuviera varias relaciones entre los mismos tipos (por ejemplo, supongamos que define las clases Persona y Libro, donde la clase Persona contuviera las propiedades de navegación LibrosRevisados y LibrosEscritos, y la clase Libro contuviera las propiedades de navegación Autor y Revisor) deberá configurar manualmente las relaciones mediante anotaciones de datos o la API fluida. Para obtener más información, consulte Anotaciones de datos: relaciones y API fluida: relaciones.

Convención de tipos complejos

Cuando Code First detecte una definición de clase donde no se pueda deducir una clave principal ni se registren claves principales a través de anotaciones de datos o la API fluida, el tipo se registrará automáticamente como un tipo complejo. La detección de tipos complejos también requiere que el tipo no tenga propiedades que hagan referencia a tipos de entidad y que no se haga referencia desde una propiedad de colección en otro tipo. Dadas las siguientes definiciones de clase, Code First deduciría que Detalles es un tipo complejo porque no tiene ninguna clave principal.

public partial class OnsiteCourse : Course
{
    public OnsiteCourse()
    {
        Details = new Details();
    }

    public Details Details { get; set; }
}

public class Details
{
    public System.DateTime Time { get; set; }
    public string Location { get; set; }
    public string Days { get; set; }
}

Convención de cadena de conexión

Para obtener más información sobre las convenciones que DbContext usa para detectar la conexión que se usará, consulte Conexiones y modelos.

Quitar convenciones

Es posible quitar cualquiera de las convenciones definidas en el espacio de nombres System.Data.Entity.ModelConfiguration.Conventions. En el ejemplo siguiente, se quita PluralizingTableNameConvention.

public class SchoolEntities : DbContext
{
     . . .

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // Configure Code First to ignore PluralizingTableName convention
        // If you keep this convention, the generated tables  
        // will have pluralized names.
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    }
}

Convenciones personalizadas

Las convenciones personalizadas se admiten en EF6 y versiones posteriores. Para obtener más información, consulte Convenciones de Code First personalizadas.