Anotaciones de datos de Code FirstCode First Data Annotations

Nota

EF 4.1 en adelante solo : las características, las API, etc. que se describen en esta página se introdujeron en Entity Framework 4,1.EF4.1 Onwards Only - The features, APIs, etc. discussed in this page were introduced in Entity Framework 4.1. Si usa una versión anterior, no se aplicará parte o toda esta información.If you are using an earlier version, some or all of this information does not apply.

El contenido de esta página se adapta a un artículo escrito originalmente por Julia Lerman ( <http://thedatafarm.com> ).The content on this page is adapted from an article originally written by Julie Lerman (<http://thedatafarm.com>).

Entity Framework Code First le permite usar sus propias clases de dominio para representar el modelo en el que se basa EF para realizar consultas, seguimiento de cambios y funciones de actualización.Entity Framework Code First allows you to use your own domain classes to represent the model that EF relies on to perform querying, change tracking, and updating functions. Code First aprovecha un patrón de programación denominado "Convención sobre configuración".Code First leverages a programming pattern referred to as 'convention over configuration.' Code First asumirá que las clases siguen las convenciones de Entity Framework y, en ese caso, se descargará automáticamente de cómo realizar su trabajo.Code First will assume that your classes follow the conventions of Entity Framework, and in that case, will automatically work out how to perform its job. Sin embargo, si las clases no siguen esas convenciones, tiene la posibilidad de agregar configuraciones a las clases para proporcionar a EF la información necesaria.However, if your classes do not follow those conventions, you have the ability to add configurations to your classes to provide EF with the requisite information.

Code First ofrece dos maneras de agregar estas configuraciones a las clases.Code First gives you two ways to add these configurations to your classes. Uno es el uso de atributos simples denominado DataAnnotations y el segundo es el uso de la API fluida de Code First, que proporciona una manera de describir las configuraciones de forma imperativa, en el código.One is using simple attributes called DataAnnotations, and the second is using Code First’s Fluent API, which provides you with a way to describe configurations imperatively, in code.

En este artículo se centrará en el uso de DataAnnotations (en el espacio de nombres System. ComponentModel. DataAnnotations) para configurar las clases, resaltando las configuraciones más necesarias.This article will focus on using DataAnnotations (in the System.ComponentModel.DataAnnotations namespace) to configure your classes – highlighting the most commonly needed configurations. Las anotaciones también se entienden en una serie de aplicaciones .NET, como ASP.NET MVC, que permite a estas aplicaciones aprovechar las mismas anotaciones para las validaciones del lado cliente.DataAnnotations are also understood by a number of .NET applications, such as ASP.NET MVC which allows these applications to leverage the same annotations for client-side validations.

El modeloThe model

Mostraré Code First DataAnnotations con un par sencillo de clases: blog y publicación.I’ll demonstrate Code First DataAnnotations with a simple pair of classes: Blog and Post.

    public class Blog
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string BloggerName { get; set;}
        public virtual ICollection<Post> Posts { get; set; }
    }

    public class Post
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public DateTime DateCreated { get; set; }
        public string Content { get; set; }
        public int BlogId { get; set; }
        public ICollection<Comment> Comments { get; set; }
    }

Como están, las clases blog y post siguen la Convención Code First de manera cómoda y no requieren ajustes para habilitar la compatibilidad con EF.As they are, the Blog and Post classes conveniently follow code first convention and require no tweaks to enable EF compatability. Sin embargo, también puede usar las anotaciones para proporcionar más información a EF sobre las clases y la base de datos a las que se asignan.However, you can also use the annotations to provide more information to EF about the classes and the database to which they map.

 

ClaveKey

Entity Framework se basa en cada entidad que tiene un valor de clave que se usa para el seguimiento de entidades.Entity Framework relies on every entity having a key value that is used for entity tracking. Una Convención de Code First son las propiedades de clave IMPLÍCITAS; Code First buscará una propiedad denominada "ID" o una combinación de nombre de clase e "ID", como "BlogId".One convention of Code First is implicit key properties; Code First will look for a property named “Id”, or a combination of class name and “Id”, such as “BlogId”. Esta propiedad se asignará a una columna de clave principal en la base de datos.This property will map to a primary key column in the database.

Las clases blog y post siguen esta Convención.The Blog and Post classes both follow this convention. ¿Qué ocurre si no?What if they didn’t? ¿Qué ocurre si el blog usa el nombre PrimaryTrackingKey en su lugar, o incluso foo?What if Blog used the name PrimaryTrackingKey instead, or even foo? Si Code First no encuentra una propiedad que coincida con esta Convención, producirá una excepción debido al requisito de Entity Framework que debe tener una propiedad de clave.If code first does not find a property that matches this convention it will throw an exception because of Entity Framework’s requirement that you must have a key property. Puede usar la anotación de clave para especificar qué propiedad se va a usar como EntityKey.You can use the key annotation to specify which property is to be used as the EntityKey.

    public class Blog
    {
        [Key]
        public int PrimaryTrackingKey { get; set; }
        public string Title { get; set; }
        public string BloggerName { get; set;}
        public virtual ICollection<Post> Posts { get; set; }
    }

Si usa la característica de generación de bases de datos de Code First, la tabla de blog tendrá una columna de clave principal denominada PrimaryTrackingKey, que también se define como Identity de forma predeterminada.If you are using code first’s database generation feature, the Blog table will have a primary key column named PrimaryTrackingKey, which is also defined as Identity by default.

Tabla de blog con clave principal

Claves compuestasComposite keys

Entity Framework admite claves compuestas: las claves principales que se componen de más de una propiedad.Entity Framework supports composite keys - primary keys that consist of more than one property. Por ejemplo, podría tener una clase de Passport cuya clave principal sea una combinación de PassportNumber y IssuingCountry.For example, you could have a Passport class whose primary key is a combination of PassportNumber and IssuingCountry.

    public class Passport
    {
        [Key]
        public int PassportNumber { get; set; }
        [Key]
        public string IssuingCountry { get; set; }
        public DateTime Issued { get; set; }
        public DateTime Expires { get; set; }
    }

Si se intenta usar la clase anterior en el modelo EF, se produciría una InvalidOperationException :Attempting to use the above class in your EF model would result in an InvalidOperationException:

No se puede determinar el orden de claves principales compuesto para el tipo ' Passport '. Use el método ColumnAttribute o Haskey (para especificar un orden para las claves principales compuestas.Unable to determine composite primary key ordering for type 'Passport'. Use the ColumnAttribute or the HasKey method to specify an order for composite primary keys.

Para usar las claves compuestas, Entity Framework requiere definir un orden para las propiedades de clave.In order to use composite keys, Entity Framework requires you to define an order for the key properties. Puede hacerlo mediante la anotación de columna para especificar un orden.You can do this by using the Column annotation to specify an order.

Nota

El valor del orden es relativo (en lugar de basado en índice), por lo que se pueden usar los valores.The order value is relative (rather than index based) so any values can be used. Por ejemplo, 100 y 200 serían aceptables en lugar de 1 y 2.For example, 100 and 200 would be acceptable in place of 1 and 2.

    public class Passport
    {
        [Key]
        [Column(Order=1)]
        public int PassportNumber { get; set; }
        [Key]
        [Column(Order = 2)]
        public string IssuingCountry { get; set; }
        public DateTime Issued { get; set; }
        public DateTime Expires { get; set; }
    }

Si tiene entidades con claves externas compuestas, debe especificar la misma ordenación de columnas que usó para las propiedades de clave principal correspondientes.If you have entities with composite foreign keys, then you must specify the same column ordering that you used for the corresponding primary key properties.

Solo el orden relativo dentro de las propiedades de clave externa debe ser el mismo, no es necesario que coincidan los valores exactos asignados al pedido .Only the relative ordering within the foreign key properties needs to be the same, the exact values assigned to Order do not need to match. Por ejemplo, en la clase siguiente, se podría usar 3 y 4 en lugar de 1 y 2.For example, in the following class, 3 and 4 could be used in place of 1 and 2.

    public class PassportStamp
    {
        [Key]
        public int StampId { get; set; }
        public DateTime Stamped { get; set; }
        public string StampingCountry { get; set; }

        [ForeignKey("Passport")]
        [Column(Order = 1)]
        public int PassportNumber { get; set; }

        [ForeignKey("Passport")]
        [Column(Order = 2)]
        public string IssuingCountry { get; set; }

        public Passport Passport { get; set; }
    }

RequeridoRequired

La Required anotación indica a EF que se requiere una propiedad determinada.The Required annotation tells EF that a particular property is required.

Agregar obligatorio a la propiedad title forzará a EF (y MVC) a asegurarse de que la propiedad contiene datos.Adding Required to the Title property will force EF (and MVC) to ensure that the property has data in it.

    [Required]
    public string Title { get; set; }

Sin ningún cambio de código o marcado adicional en la aplicación, una aplicación MVC realizará la validación del lado cliente, incluso generando dinámicamente un mensaje usando los nombres de la propiedad y de las anotaciones.With no additional code or markup changes in the application, an MVC application will perform client side validation, even dynamically building a message using the property and annotation names.

La página crear con el título es un error necesario

El atributo required también afectará a la base de datos generada haciendo que la propiedad asignada no acepte valores NULL.The Required attribute will also affect the generated database by making the mapped property non-nullable. Observe que el campo title ha cambiado a "not null".Notice that the Title field has changed to “not null”.

Nota

En algunos casos, es posible que no sea posible que la columna de la base de datos no acepte valores NULL, aunque se requiera la propiedad.In some cases it may not be possible for the column in the database to be non-nullable even though the property is required. Por ejemplo, cuando se usa un dato de estrategia de herencia de TPH para varios tipos, se almacena en una sola tabla.For example, when using a TPH inheritance strategy data for multiple types is stored in a single table. Si un tipo derivado incluye una propiedad necesaria, no se puede hacer que la columna no acepte valores NULL, ya que no todos los tipos de la jerarquía tendrán esta propiedad.If a derived type includes a required property the column cannot be made non-nullable since not all types in the hierarchy will have this property.

 

Tabla de blogs

 

MaxLength y MinLengthMaxLength and MinLength

Los MaxLength MinLength atributos y permiten especificar validaciones de propiedades adicionales, tal como se hizo con Required .The MaxLength and MinLength attributes allow you to specify additional property validations, just as you did with Required.

Este es el BloggerName con los requisitos de longitud.Here is the BloggerName with length requirements. En el ejemplo también se muestra cómo combinar atributos.The example also demonstrates how to combine attributes.

    [MaxLength(10),MinLength(5)]
    public string BloggerName { get; set; }

La anotación MaxLength afectará a la base de datos estableciendo la longitud de la propiedad en 10.The MaxLength annotation will impact the database by setting the property’s length to 10.

Tabla de blogs que muestra la longitud máxima de la columna BloggerName

La anotación del lado cliente de MVC y la anotación del lado servidor EF 4,1 respetarán esta validación y, de nuevo, se generará dinámicamente un mensaje de error: "el campo BloggerName debe ser una cadena o un tipo de matriz con una longitud máxima de ' 10 '". Ese mensaje es un poco largo.MVC client-side annotation and EF 4.1 server-side annotation will both honor this validation, again dynamically building an error message: “The field BloggerName must be a string or array type with a maximum length of '10'.” That message is a little long. Muchas anotaciones permiten especificar un mensaje de error con el atributo ErrorMessage.Many annotations let you specify an error message with the ErrorMessage attribute.

    [MaxLength(10, ErrorMessage="BloggerName must be 10 characters or less"),MinLength(5)]
    public string BloggerName { get; set; }

También puede especificar ErrorMessage en la anotación requerida.You can also specify ErrorMessage in the Required annotation.

Crear página con mensaje de error personalizado

 

NotMappedNotMapped

La Convención Code First dicta que cada propiedad que es de un tipo de datos admitido se representa en la base de datos.Code first convention dictates that every property that is of a supported data type is represented in the database. Pero esto no siempre es el caso en las aplicaciones.But this isn’t always the case in your applications. Por ejemplo, podría tener una propiedad en la clase de blog que crea un código basado en los campos título y BloggerName.For example you might have a property in the Blog class that creates a code based on the Title and BloggerName fields. Esa propiedad se puede crear dinámicamente y no es necesario almacenarla.That property can be created dynamically and does not need to be stored. Puede marcar las propiedades que no se asignan a la base de datos con la anotación NotMapped como esta propiedad BlogCode.You can mark any properties that do not map to the database with the NotMapped annotation such as this BlogCode property.

    [NotMapped]
    public string BlogCode
    {
        get
        {
            return Title.Substring(0, 1) + ":" + BloggerName.Substring(0, 1);
        }
    }

 

ComplexTypeComplexType

No es raro describir las entidades de dominio en un conjunto de clases y, a continuación, crear capas de esas clases para describir una entidad completa.It’s not uncommon to describe your domain entities across a set of classes and then layer those classes to describe a complete entity. Por ejemplo, puede Agregar una clase denominada BlogDetails al modelo.For example, you may add a class called BlogDetails to your model.

    public class BlogDetails
    {
        public DateTime? DateCreated { get; set; }

        [MaxLength(250)]
        public string Description { get; set; }
    }

Tenga en cuenta que no BlogDetails tiene ningún tipo de propiedad de clave.Notice that BlogDetails does not have any type of key property. En el diseño controlado por dominios, BlogDetails se conoce como objeto de valor.In domain driven design, BlogDetails is referred to as a value object. Entity Framework hace referencia a los objetos de valor como tipos complejos.Entity Framework refers to value objects as complex types.No se puede realizar un seguimiento de los tipos complejos por su cuenta.  Complex types cannot be tracked on their own.

Sin embargo, como una propiedad de la Blog clase, se BlogDetails realizará un seguimiento como parte de un Blog objeto.However as a property in the Blog class, BlogDetails will be tracked as part of a Blog object. Para que Code First lo reconozca, debe marcar la BlogDetails clase como ComplexType .In order for code first to recognize this, you must mark the BlogDetails class as a ComplexType.

    [ComplexType]
    public class BlogDetails
    {
        public DateTime? DateCreated { get; set; }

        [MaxLength(250)]
        public string Description { get; set; }
    }

Ahora puede Agregar una propiedad en la Blog clase para representar el BlogDetails para ese blog.Now you can add a property in the Blog class to represent the BlogDetails for that blog.

        public BlogDetails BlogDetail { get; set; }

En la base de datos, la tabla contendrá Blog todas las propiedades del blog, incluidas las propiedades contenidas en su BlogDetail propiedad.In the database, the Blog table will contain all of the properties of the blog including the properties contained in its BlogDetail property. De forma predeterminada, cada uno está precedido por el nombre del tipo complejo, "BlogDetail".By default, each one is preceded with the name of the complex type, "BlogDetail".

Tabla de blog con tipo complejo

ConcurrencyCheckConcurrencyCheck

La ConcurrencyCheck anotación permite marcar una o más propiedades que se usarán para la comprobación de simultaneidad en la base de datos cuando un usuario edita o elimina una entidad.The ConcurrencyCheck annotation allows you to flag one or more properties to be used for concurrency checking in the database when a user edits or deletes an entity. Si ha estado trabajando con EF Designer, esto se alinea con el establecimiento de la propiedad ConcurrencyMode en Fixed .If you've been working with the EF Designer, this aligns with setting a property's ConcurrencyMode to Fixed.

Veamos cómo ConcurrencyCheck funciona agregándolo a la BloggerName propiedad.Let’s see how ConcurrencyCheck works by adding it to the BloggerName property.

    [ConcurrencyCheck, MaxLength(10, ErrorMessage="BloggerName must be 10 characters or less"),MinLength(5)]
    public string BloggerName { get; set; }

Cuando SaveChanges se llama a, debido a la ConcurrencyCheck anotación en el BloggerName campo, se usará el valor original de dicha propiedad en la actualización.When SaveChanges is called, because of the ConcurrencyCheck annotation on the BloggerName field, the original value of that property will be used in the update. El comando intentará buscar la fila correcta filtrando no solo en el valor de clave, sino también en el valor original de BloggerName .The command will attempt to locate the correct row by filtering not only on the key value but also on the original value of BloggerName.Estas son las partes fundamentales del comando UPDATE que se envía a la base de datos, donde puede ver que el comando actualizará la fila que tiene el PrimaryTrackingKey valor 1 y un BloggerName de "Julia", que era el valor original cuando el blog se recuperó de la base de datos.  Here are the critical parts of the UPDATE command sent to the database, where you can see the command will update the row that has a PrimaryTrackingKey is 1 and a BloggerName of “Julie” which was the original value when that blog was retrieved from the database.

    where (([PrimaryTrackingKey] = @4) and ([BloggerName] = @5))
    @4=1,@5=N'Julie'

Si un usuario ha cambiado el nombre de blogger para ese blog mientras tanto, se producirá un error en esta actualización y obtendrá un DbUpdateConcurrencyException que deberá controlar.If someone has changed the blogger name for that blog in the meantime, this update will fail and you’ll get a DbUpdateConcurrencyException that you'll need to handle.

 

TimeStampTimeStamp

Es más común usar los campos rowversion o TIMESTAMP para la comprobación de simultaneidad.It's more common to use rowversion or timestamp fields for concurrency checking. Pero en lugar de utilizar la ConcurrencyCheck anotación, puede usar la anotación más específica siempre que TimeStamp el tipo de la propiedad sea una matriz de bytes.But rather than using the ConcurrencyCheck annotation, you can use the more specific TimeStamp annotation as long as the type of the property is byte array. Code First tratará las Timestamp Propiedades igual que ConcurrencyCheck las propiedades, pero también se asegurará de que el campo de base de datos generado por Code First no admita valores NULL.Code first will treat Timestamp properties the same as ConcurrencyCheck properties, but it will also ensure that the database field that code first generates is non-nullable. Solo puede tener una propiedad timestamp en una clase determinada.You can only have one timestamp property in a given class.

Agregando la siguiente propiedad a la clase de blog:Adding the following property to the Blog class:

    [Timestamp]
    public Byte[] TimeStamp { get; set; }

en primer lugar, el código crea una columna de marca de tiempo que no acepta valores NULL en la tabla de base de datos.results in code first creating a non-nullable timestamp column in the database table.

Tabla de blogs con columna de marca de tiempo

 

Tabla y columnaTable and Column

Si va a permitir que Code First cree la base de datos, puede que desee cambiar el nombre de las tablas y columnas que está creando.If you are letting Code First create the database, you may want to change the name of the tables and columns it is creating. También puede usar Code First con una base de datos existente.You can also use Code First with an existing database. Pero no siempre es el caso de que los nombres de las clases y propiedades de su dominio coincidan con los nombres de las tablas y columnas de la base de datos.But it's not always the case that the names of the classes and properties in your domain match the names of the tables and columns in your database.

Mi clase se denomina Blog y por Convención, Code First presupone que se asignará a una tabla denominada Blogs .My class is named Blog and by convention, code first presumes this will map to a table named Blogs. Si no es así, puede especificar el nombre de la tabla con el Table atributo.If that's not the case you can specify the name of the table with the Table attribute. Aquí, por ejemplo, la anotación está especificando que el nombre de la tabla es InternalBlogs.Here for example, the annotation is specifying that the table name is InternalBlogs.

    [Table("InternalBlogs")]
    public class Blog

La Column anotación es más bien para especificar los atributos de una columna asignada.The Column annotation is a more adept in specifying the attributes of a mapped column. Puede estipular un nombre, un tipo de datos o incluso el orden en el que aparece una columna en la tabla.You can stipulate a name, data type or even the order in which a column appears in the table. Este es un ejemplo del Column atributo.Here is an example of the Column attribute.

    [Column("BlogDescription", TypeName="ntext")]
    public String Description {get;set;}

No confunda TypeName el atributo de la columna con la anotación DataType.Don’t confuse Column’s TypeName attribute with the DataType DataAnnotation. DataType es una anotación que se usa para la interfaz de usuario y Code First omitirá.DataType is an annotation used for the UI and is ignored by Code First.

Esta es la tabla una vez regenerada.Here is the table after it’s been regenerated. El nombre de la tabla ha cambiado a InternalBlogs y Description la columna del tipo complejo es ahora BlogDescription .The table name has changed to InternalBlogs and Description column from the complex type is now BlogDescription. Dado que el nombre se especificó en la anotación, Code First no usará la Convención de inicio del nombre de columna con el nombre del tipo complejo.Because the name was specified in the annotation, code first will not use the convention of starting the column name with the name of the complex type.

Nombre de tabla y columna de blogs

 

DatabaseGeneratedDatabaseGenerated

Una característica importante de las bases de datos es la capacidad de tener propiedades calculadas.An important database features is the ability to have computed properties. Si va a asignar las clases de Code First a tablas que contienen columnas calculadas, no desea que Entity Framework intente actualizar esas columnas.If you're mapping your Code First classes to tables that contain computed columns, you don't want Entity Framework to try to update those columns. Pero quiere que EF devuelva los valores de la base de datos después de insertar o actualizar los datos.But you do want EF to return those values from the database after you've inserted or updated data. Puede usar la DatabaseGenerated anotación para marcar esas propiedades en la clase junto con la Computed enumeración.You can use the DatabaseGenerated annotation to flag those properties in your class along with the Computed enum. Otras enumeraciones son None y Identity .Other enums are None and Identity.

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DateTime DateCreated { get; set; }

Puede usar la base de datos generada en columnas de tipo byte o TIMESTAMP cuando Code First está generando la base de datos; de lo contrario, solo debería usar esta al apuntar a bases de datos existentes porque Code First no podrá determinar la fórmula de la columna calculada.You can use database generated on byte or timestamp columns when code first is generating the database, otherwise you should only use this when pointing to existing databases because code first won't be able to determine the formula for the computed column.

Antes de que lea de forma predeterminada, una propiedad clave que es un entero se convertirá en una clave de identidad en la base de datos.You read above that by default, a key property that is an integer will become an identity key in the database. Es lo mismo que establecer DatabaseGenerated en DatabaseGeneratedOption.Identity .That would be the same as setting DatabaseGenerated to DatabaseGeneratedOption.Identity. Si no desea que sea una clave de identidad, puede establecer el valor en DatabaseGeneratedOption.None .If you do not want it to be an identity key, you can set the value to DatabaseGeneratedOption.None.

 

ÍndiceIndex

Nota

EF 6.1 en adelante solo : el Index atributo se presentó en Entity Framework 6,1.EF6.1 Onwards Only - The Index attribute was introduced in Entity Framework 6.1. Si usa una versión anterior, no se aplica la información de esta sección.If you are using an earlier version the information in this section does not apply.

Puede crear un índice en una o más columnas mediante IndexAttribute.You can create an index on one or more columns using the IndexAttribute. Si se agrega el atributo a una o varias propiedades, EF creará el índice correspondiente en la base de datos al crear la base de datos, o scaffolding, las llamadas CreateIndex correspondientes si usa migraciones de Code First.Adding the attribute to one or more properties will cause EF to create the corresponding index in the database when it creates the database, or scaffold the corresponding CreateIndex calls if you are using Code First Migrations.

Por ejemplo, el código siguiente generará un índice que se creará en la Rating columna de la Posts tabla de la base de datos.For example, the following code will result in an index being created on the Rating column of the Posts table in the database.

    public class Post
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }
        [Index]
        public int Rating { get; set; }
        public int BlogId { get; set; }
    }

De forma predeterminada, el índice se denominará ** _ < nombre > de propiedad IX** (clasificación IX _ en el ejemplo anterior).By default, the index will be named IX_<property name> (IX_Rating in the above example). No obstante, también puede especificar un nombre para el índice.You can also specify a name for the index though. En el ejemplo siguiente se especifica que el índice se debe denominar PostRatingIndex .The following example specifies that the index should be named PostRatingIndex.

    [Index("PostRatingIndex")]
    public int Rating { get; set; }

De forma predeterminada, los índices no son únicos, pero puede usar el IsUnique parámetro con nombre para especificar que un índice debe ser único.By default, indexes are non-unique, but you can use the IsUnique named parameter to specify that an index should be unique. En el ejemplo siguiente se presenta un índice único en el User nombre de inicio de sesión de.The following example introduces a unique index on a User's login name.

    public class User
    {
        public int UserId { get; set; }

        [Index(IsUnique = true)]
        [StringLength(200)]
        public string Username { get; set; }

        public string DisplayName { get; set; }
    }

Índices de Multiple-ColumnMultiple-Column Indexes

Los índices que abarcan varias columnas se especifican utilizando el mismo nombre en varias anotaciones de índice para una tabla determinada.Indexes that span multiple columns are specified by using the same name in multiple Index annotations for a given table. Al crear índices de varias columnas, debe especificar un orden para las columnas en el índice.When you create multi-column indexes, you need to specify an order for the columns in the index. Por ejemplo, el código siguiente crea un índice de varias columnas en Rating y BlogId denominado IX _ BlogIdAndRating.For example, the following code creates a multi-column index on Rating and BlogId called IX_BlogIdAndRating. BlogId es la primera columna del índice y Rating es el segundo.BlogId is the first column in the index and Rating is the second.

    public class Post
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }
        [Index("IX_BlogIdAndRating", 2)]
        public int Rating { get; set; }
        [Index("IX_BlogIdAndRating", 1)]
        public int BlogId { get; set; }
    }

 

Atributos de relación: InverseProperty y ForeignKeyRelationship Attributes: InverseProperty and ForeignKey

Nota

En esta página se proporciona información sobre cómo configurar las relaciones en el modelo de Code First con anotaciones de datos.This page provides information about setting up relationships in your Code First model using Data Annotations. Para obtener información general sobre las relaciones en EF y cómo obtener acceso a los datos y manipularlos mediante relaciones, vea relaciones & propiedades de navegación. *For general information about relationships in EF and how to access and manipulate data using relationships, see Relationships & Navigation Properties.*

La Convención Code First se encargará de las relaciones más comunes del modelo, pero hay algunos casos en los que necesita ayuda.Code first convention will take care of the most common relationships in your model, but there are some cases where it needs help.

Cambiar el nombre de la propiedad de clave en la Blog clase creó un problema con su relación con Post .Changing the name of the key property in the Blog class created a problem with its relationship to Post. 

Al generar la base de datos, Code First ve la BlogId propiedad en la clase post y la reconoce, por la Convención que coincide con un nombre de clase más ID, como una clave externa a la Blog clase.When generating the database, code first sees the BlogId property in the Post class and recognizes it, by the convention that it matches a class name plus Id, as a foreign key to the Blog class. Pero no hay ninguna BlogId propiedad en la clase de blog.But there is no BlogId property in the blog class. La solución para esto es crear una propiedad de navegación en Post y utilizar la anotación de datos ForeignKey para que el código de ayuda comprenda primero cómo crear la relación entre las dos clases (mediante la Post.BlogId propiedad) y cómo especificar restricciones en la base de datos.The solution for this is to create a navigation property in the Post and use the ForeignKey DataAnnotation to help code first understand how to build the relationship between the two classes (using the Post.BlogId property) as well as how to specify constraints in the database.

    public class Post
    {
            public int Id { get; set; }
            public string Title { get; set; }
            public DateTime DateCreated { get; set; }
            public string Content { get; set; }
            public int BlogId { get; set; }
            [ForeignKey("BlogId")]
            public Blog Blog { get; set; }
            public ICollection<Comment> Comments { get; set; }
    }

La restricción en la base de datos muestra una relación entre InternalBlogs.PrimaryTrackingKey y Posts.BlogId .The constraint in the database shows a relationship between InternalBlogs.PrimaryTrackingKey and Posts.BlogId. 

relación entre InternalBlogs. PrimaryTrackingKey y posts. BlogId

InversePropertySe usa cuando se tienen varias relaciones entre las clases.The InverseProperty is used when you have multiple relationships between classes.

En la Post clase, puede que desee realizar un seguimiento de quién escribió una entrada de blog y quién la editó.In the Post class, you may want to keep track of who wrote a blog post as well as who edited it. A continuación se muestran dos nuevas propiedades de navegación para la clase post.Here are two new navigation properties for the Post class.

    public Person CreatedBy { get; set; }
    public Person UpdatedBy { get; set; }

También necesitará agregar en la clase a la Person que hacen referencia estas propiedades.You’ll also need to add in the Person class referenced by these properties. La Person clase tiene propiedades de navegación de vuelta a Post , una para todas las publicaciones escritas por la persona y otra para todas las entradas actualizadas por esa persona.The Person class has navigation properties back to the Post, one for all of the posts written by the person and one for all of the posts updated by that person.

    public class Person
    {
            public int Id { get; set; }
            public string Name { get; set; }
            public List<Post> PostsWritten { get; set; }
            public List<Post> PostsUpdated { get; set; }
    }

Code First no puede hacer coincidir las propiedades de las dos clases por sí mismas.Code first is not able to match up the properties in the two classes on its own. La tabla de base de datos de Posts debe tener una clave externa para la CreatedBy persona y otra para la UpdatedBy persona, pero Code First creará cuatro propiedades de clave externa: Person _ ID, Person _ Id1, CreatedBy _ ID e UpdatedBy _ ID.The database table for Posts should have one foreign key for the CreatedBy person and one for the UpdatedBy person but code first will create four foreign key properties: Person_Id, Person_Id1, CreatedBy_Id and UpdatedBy_Id.

Tabla de publicaciones con claves externas adicionales

Para corregir estos problemas, puede usar la InverseProperty anotación para especificar la alineación de las propiedades.To fix these problems, you can use the InverseProperty annotation to specify the alignment of the properties.

    [InverseProperty("CreatedBy")]
    public List<Post> PostsWritten { get; set; }

    [InverseProperty("UpdatedBy")]
    public List<Post> PostsUpdated { get; set; }

Dado PostsWritten que la propiedad en persona sabe que esto hace referencia al Post tipo, creará la relación con Post.CreatedBy .Because the PostsWritten property in Person knows that this refers to the Post type, it will build the relationship to Post.CreatedBy. Del mismo modo, se PostsUpdated conectará a Post.UpdatedBy .Similarly, PostsUpdated will be connected to Post.UpdatedBy. Y Code First no crearán las claves externas adicionales.And code first will not create the extra foreign keys.

Tabla de publicaciones sin claves externas adicionales

 

ResumenSummary

Las DataAnnotations no solo permiten describir la validación del lado cliente y del servidor en las clases Code First, sino que también permiten mejorar e incluso corregir las suposiciones que Code First realizará sobre las clases en función de sus convenciones.DataAnnotations not only let you describe client and server side validation in your code first classes, but they also allow you to enhance and even correct the assumptions that code first will make about your classes based on its conventions. Con DataAnnotations no solo puede controlar la generación de esquemas de base de datos, sino que también puede asignar las clases Code First a una base de datos existente previamente.With DataAnnotations you can not only drive database schema generation, but you can also map your code first classes to a pre-existing database.

Aunque son muy flexibles, tenga en cuenta que las anotaciones solo proporcionan los cambios de configuración más necesarios que se pueden realizar en las clases Code First.While they are very flexible, keep in mind that DataAnnotations provide only the most commonly needed configuration changes you can make on your code first classes. Para configurar las clases para algunos de los casos extremos, debe buscar el mecanismo de configuración alternativo, la API fluida de Code First.To configure your classes for some of the edge cases, you should look to the alternate configuration mechanism, Code First’s Fluent API .