¿Cómo creo una tabla de Code-First Entity Framework 4.3 Many-To-Many con columnas adicionales?

Tengo las siguientes clases en un Entity Framework 4.3 Code-First Model para MVC3:

public class Film
{
    public Int32 ID { get; set; }

    [Column("FilmName"), MinLength(2), MaxLength(100)]
    [Required(ErrorMessage = "Please enter a name")]
    public String Name { get; set; }

    public Model.Cast Cast { get; set; }
}

public class Actor
{
    public Int32 ID { get; set; }

    [MaxLength(75)]
    public String Name { get; set; }
}

[Table("Cast")]
public class Cast
{
    public Actor Actor { get; set; }

    [MaxLength(500)]
    public String Role { get; set; }

    public virtual Film Film { get; set; }
}

Quiero un diseño de tabla como el siguiente resultado:

Films:
ID PK
Name

Cast:
FilmID PK FK
ActorID PK FK
Role

Actors:
ID PK
Name

¿Cómo puedo hacer que se cree la tabla Cast? Me sale el siguiente error en este momento:

##System.Data.Entity.Edm.EdmEntityType: : EntityType 'Cast' no tiene clave definida. Defina la clave para este EntityType. \tSystem.Data.Entity.Edm.EdmEntitySet: EntityType: EntitySet 'Casts' se basa en el tipo 'Cast' que no tiene claves definidas.##

Pero no quiero crear una clave de ID, quiero usar los campos de ID de Film y Actor para crear una clave principal compuesta, las cuales son claves foráneas para las otras tablas.

¿Qué debo hacer?

preguntado el 22 de mayo de 12 a las 19:05

2 Respuestas

Debes redefinir tu modelo de esta manera:

public class Film
{
    public Int32 ID { get; set; }

    [Column("FilmName"), MinLength(2), MaxLength(100)]
    [Required(ErrorMessage = "Please enter a name")]
    public String Name { get; set; }

    public ICollection<Model.Cast> Cast { get; set; }
}

public class Actor
{
    public Int32 ID { get; set; }

    [MaxLength(75)]
    public String Name { get; set; }


    public ICollection<Model.Cast> Cast { get; set; }
}

[Table("Cast")]
public class Cast
{
    [Key, Column(Order = 0)]
    public int ActorId { get; set; }
    [Key, Column(Order = 1)]
    public int FilmId { get; set; }

    [MaxLength(500)]
    public String Role { get; set; }

    [ForeignKey("ActorId")]
    public Actor Actor { get; set; }
    [ForeignKey("FilmId")]
    public virtual Film Film { get; set; }
}

contestado el 23 de mayo de 12 a las 09:05

Genial, muchas gracias. De hecho, había probado este método pero no había incluido public ICollection<Model.Cast> Cast { get; set; } en la clase Actor. Muy apreciado. - robar rey

Is public ICollection<Model.Cast> Cast { get; set; } destinado a ser virtual? - robar rey

Sí, hazlo virtual si quieres usar la carga diferida. - Ladislav Mrnka

He intentado hacer esto antes sin éxito. Mi solución fue mapear la tabla de enlaces como una entidad normal con su propia identidad PK y personalizar DatabaseInitializer para ejecutar un script DDL para crear un índice único para los FK. Supongo que EF no fue diseñado para admitir este tipo de mapeo heredado.

contestado el 22 de mayo de 12 a las 19:05

No es un mapeo heredado, es una forma perfectamente válida de normalizar una base de datos. Afortunadamente, hubo una solución, ya que era importante que se modelara de esta manera. - robar rey

Tal vez no me expresé bien... por ejemplo, la mayoría de OODMBS requiere que cada tabla tenga su propia clave única, un solo campo como identificador único de cada fila (objeto). Dado que estamos utilizando ORM para asignar bases de datos relacionales a objetos de dominio/modelo de nuestras aplicaciones, siempre existe la famosa impedancia de desajuste sobre cómo creamos tablas de base de datos y cómo creamos clases que representan estas tablas. Por esta razón llamé mapeo heredado, sin ofender. A veces es más fácil crear tablas en la base de datos de una manera que se acerque más a nuestras clases, solo para facilitar el mapeo. Mañana o más tarde, EF puede cambiar. - jone polvora

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.