2010-09-01 13 views

Respuesta

11

¿Estás buscando algo como esto?

public class User 
{ 
    public int Id { get; set; } 
    public string Username { get; set; } 
    public Profile Profile { get; set; } 
    public int ProfileId { get; set; } 
} 

public class Profile 
{ 
    public int Id { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public string PostalCode { get; set; } 
    // etc... 
} 

public class UserMapping : EntityConfiguration<User> 
{ 
    public UserMapping() 
    { 
     this.HasKey(u => u.Id); 
     this.Property(u => u.Username).HasMaxLength(32); 

     // User has ONE profile. 
     this.HasRequired(u => u.Profile); 
    } 
} 

public class ProfileMapping : EntityConfiguration<Profile> 
{ 
    public ProfileMapping() 
    { 
     this.HasKey(p => p.Id); 
     this.Property(p => p.FirstName).HasMaxLength(32); 
     this.Property(p => p.LastName).HasMaxLength(32); 
     this.Property(p => p.PostalCode).HasMaxLength(6); 
    } 
} 

EDITAR: Sí no tenía VS frente a mí, pero es necesario añadir la siguiente línea en el UserMapping en lugar del actual HasRequired y también añadir una propiedad ProfileId (en lugar de que Profile_Id agregado):

this.HasRequired(u => u.Profile).HasConstraint((u, p) => u.ProfileId == p.Id); 

que actualmente no creo que haya una forma de evitar esto, pero estoy seguro de que va a cambiar ya que estamos sólo en CTP4. Sería bueno si pudiera decir:

this.HasRequired(u => u.Profile).WithSingle().Map(
    new StoreForeignKeyName("ProfileId")); 

De esta manera no tendría que incluir una propiedad ProfileId. Tal vez hay una forma de evitar esto actualmente y todavía es temprano para que yo piense :).

Recuerde también llamar al .Include("Profile") si desea incluir una "propiedad de navegación".

+0

¿Esto funciona para usted? No puedo hacer que funcione. No estoy generando la base de datos automáticamente ya que tengo tablas existentes. Mi tabla de perfil tiene Id como PK y FK (ya que la relación es 1: 1). Supongo que esto es lo mismo que tú. Si intento ejecutar su código, aparece un error: Nombre de columna inválido 'Profile_Id'. Si agrego esa columna al usuario (no es que la quiera allí), se devuelve el usuario pero el perfil es nulo. El SQL generado es:. SELECT [Extent1] [Id] AS [Id], [Extent1] [nombre de usuario] AS [nombre de usuario], [Extent1] [profile_id] AS [profile_id] DE [dbo.. ]. [Usuarios] AS [Extensión1] ¿Alguna idea? –

+0

hmm. En la segunda inspección, parece que funciona bien en sqlce4, pero no en SQL server 2010 a menos que me falta algo. –

+1

@ zaph0d - Si desea acceder a una propiedad que es "otra entidad", debe "incluirla". La forma de hacerlo sería 'context.Users.Include (" Profile ")'. El perfil es una "propiedad de navegación" que requerirá un JOIN en SQL. He editado mi publicación con la información adicional que olvidé para el perfil. – TheCloudlessSky

1
public class User 
{ 
    public int Id { get; set; } 
    public string Username { get; set; } 

    public virtual Profile Profile { get; set; } 
} 

public class Profile 
{ 
    public int Id { get; set; } 

    public int UserID { get; set; } 

    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public string PostalCode { get; set; } 
} 

Agregue el perfil virtual y el ID de usuario, y creo que eso debería llevarlo allí.

+2

¿No sería esa una relación de uno a muchos? La pregunta fue aproximadamente 1: 1. – saille

+0

No, no lo es. es 1: 1 Un usuario tiene 1 perfil en este ejemplo ... Si no he entendido mal algo por completo. – BjarkeCK

22

tres métodos:

A) Declarar ambas clases con propiedades de navegación entre sí. Marque una de las tablas (la tabla dependiente) con el atributo ForeignKey en su clave principal. EF infiere 1-a-1 de esta:.

public class AppUser 
{ 
    public int Id { get; set; } 

    public string Username { get; set; } 

    public OpenIdInfo OpenIdInfo { get; set; } 
} 

​public class OpenIdInfo 
{ 
    [ForeignKey("AppUser")] 
    public int Id { get; set; } 

    public string OpenId { get; set; } 

    public AppUser AppUser { get; set; } 
} 

http://weblogs.asp.net/manavi/archive/2011/05/01/associations-in-ef-4-1-code-first-part-5-one-to-one-foreign-key-associations.aspx

No utilizar virtual y usted no debe tampoco *

b) declarar una jerarquía de herencia con los dos nombres de tabla explícitamente establecido, resultando en Table-Per-Type y una clave principal compartida.

using System.ComponentModel.DataAnnotations; 

[Table("AppUser")] 
public class AppUser 
{ 
    public int Id { get; set; } 

    public string Username { get; set; } 

    public OpenIdInfo OpenIdInfo { get; set; } 
} 

[Table("AdminUser")]  
public class AdminUser : AppUser 
{ 
    public bool SuperAdmin { get; set; } 
} 

Obtendrá 2 tablas: una para AppUser, una para AdminUser. AdminUser es 1: 1 con AppUser y es Dependiente, lo que significa que puede eliminar un Usuario de administrador, pero si elimina un AppUser cuando un Usuario de Administración aún lo está apuntando, obtendrá un Error de Violación de Restricciones.

C) Hay 2 métodos de medio camino de hacer uno-a-uno en EF:

Entity-Splitting, donde se tiene una sola clase, pero se almacena en una tabla principal, y 1 o más tablas relacionadas de uno a uno.

Table-Splitting, donde un árbol de objetos se aplana en una sola mesa. Por ejemplo, una clase con una propiedad Address tendría columnas para el objeto Address, como Address_City, aplanadas en una sola tabla.

* Puede incluir virtual en cualquier propiedad EF o Colecciones if you want to lazy-load them. Esto puede dar como resultado bucles infinitos o cargar todo el DB si pasa un objeto con propiedades de carga lenta a, por ejemplo, el convertidor MVC JSON o cualquier otra cosa que recorre la jerarquía de objetos. La carga diferida siempre se realiza de forma sincronizada, bloqueando el hilo y sin previo aviso. Para resumir, la lista de formas en que puede congelar su código, aplicación o servidor con ella es larga. Evite el uso de clases virtuales en EF. Sí, hay muchas muestras de código en Internet que lo usan. No, todavía no deberías usarlo.

+0

por qué no utilizar la palabra clave 'virtual' – AminM

+0

@AminM Consulte la nota al final sobre carga lenta y virtual. –

1

Tome un ejemplo de las siguientes entidades Student y StudentAddress.
configurar uno-a-cero-o-uno utilizando DataAnnotations:

public class Student 
{ 
    public Student() { } 

    public int StudentId { get; set; } 
    public string StudentName { get; set; } 

    public virtual StudentAddress Address { get; set; } 

} 

public class StudentAddress 
{ 
    [ForeignKey("Student")] 
    public int StudentAddressId { get; set; } 

    public string Address1 { get; set; } 
    public string Address2 { get; set; } 
    public string City { get; set; } 
    public int Zipcode { get; set; } 
    public string State { get; set; } 
    public string Country { get; set; } 

    public virtual Student Student { get; set; } 
} 

Cuando entidad StudentAddress no sigue las convenciones:

Si, por ejemplo, entidad StudentAddress no sigue el convención para PK, es decir, un nombre diferente para la propiedad Id, entonces también debe configurarlo para PK. Considere la siguiente entidad StudentAddress que tiene el nombre de propiedad StudentId en lugar de StudentAddressId.

public class Student 
{ 
    public Student() { } 

    public int StudentId { get; set; } 
    public string StudentName { get; set; } 

    public virtual StudentAddress Address { get; set; } 

} 

public class StudentAddress 
{ 
    [Key, ForeignKey("Student")] 
    public int StudentId { get; set; } 

    public string Address1 { get; set; } 
    public string Address2 { get; set; } 
    public string City { get; set; } 
    public int Zipcode { get; set; } 
    public string State { get; set; } 
    public string Country { get; set; } 

    public virtual Student Student { get; set; } 
} 

En el ejemplo anterior, tenemos que configurar la propiedad de StudentId como clave y ForeignKey. Esto hará que la propiedad StudentId en la entidad StudentAddress como PK y FK ambas.

configurar uno-a-cero-o-Una relación utilizando la API de Fluido:
Cuando los estudiantes y StudentAddress siguen las convenciones: entidades estudiantiles y StudentAddress siguen la convención de código de primer defecto para PrimaryKey. Por lo tanto, no es necesario configurarlos para definir sus PrimaryKeys. Solo necesitamos configurar la entidad StudentAddress donde StudentAddressId debe ser ForeignKey.

El siguiente ejemplo establece una relación uno a cero o una relación entre Student y StudentAddress usando Fluent API.

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 

    // Configure Student & StudentAddress entity 
    modelBuilder.Entity<Student>() 
       .HasOptional(s => s.Address) // Mark Address property optional in Student entity 
       .WithRequired(ad => ad.Student); // mark Student property as required in StudentAddress entity. Cannot save StudentAddress without Student 

} 

En el ejemplo anterior, la entidad Estudiante se configura utilizando el método HasOptional() que indica que la propiedad de navegación StudentAddress en la entidad de los estudiantes es un accesorio opcional (no se requiere cuando se guarda entidad Estudiante). Luego, el método WithRequired() configura la entidad StudentAddress y crea la propiedad de navegación Student de StudentAddress según sea necesario (se requiere al guardar la entidad StudentAddress. Lanzará una excepción cuando la entidad StudentAddress esté guardando sin la propiedad de navegación del Estudiante). Esto hará que StudentAddressId también sea ForeignKey.

Por lo tanto, puede configurar una relación uno a cero entre dos entidades donde la entidad Student se puede guardar sin adjuntar el objeto StudentAddress pero la entidad StudentAddress no se puede guardar sin adjuntar un objeto de entidad Student. Esto hace que se requiera un extremo.

Cuando entidad StudentAddress no siguen las convenciones:
Ahora, vamos a dar un ejemplo de entidad StudentAddress donde no se sigue la convención clave primaria es decir, tener diferentes Id nombre de la propiedad de Id. Considere las siguientes entidades de Student y StudentAddress.

public class Student 
{ 
    public Student() { } 

    public int StudentId { get; set; } 
    public string StudentName { get; set; } 

    public virtual StudentAddress Address { get; set; } 

} 

public class StudentAddress 
{ 
    public int StudentId { get; set; } 

    public string Address1 { get; set; } 
    public string Address2 { get; set; } 
    public string City { get; set; } 
    public int Zipcode { get; set; } 
    public string State { get; set; } 
    public string Country { get; set; } 

    public virtual Student Student { get; set; } 
} 

Así que ahora, tenemos que configurar la propiedad StudentId de StudentAddress para PrimaryKey de StudentAddress, así como ForeignKey como se muestra a continuación.

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    // Configure StudentId as PK for StudentAddress 
    modelBuilder.Entity<StudentAddress>() 
     .HasKey(e => e.StudentId); 

    // Configure StudentId as FK for StudentAddress 
    modelBuilder.Entity<Student>() 
       .HasOptional(s => s.Address) 
       .WithRequired(ad => ad.Student); 

} 

configurar uno-a-uno utilizando la API de Fluido:
podemos configurar relación uno-a-uno entre entidades usando API Fluido donde se requieren los dos extremos, es decir, objeto de entidad estudiante debe incluir entidad StudentAddress La entidad object y StudentAddress debe incluir el objeto de la entidad Student para guardarlo.

Nota: La relación uno-a-uno no es técnicamente posible en MS SQL Server. Siempre será uno a cero o uno. EF forma relaciones uno-a-uno en entidades que no están en DB.

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    // Configure StudentId as PK for StudentAddress 
    modelBuilder.Entity<StudentAddress>() 
     .HasKey(e => e.StudentId); 

    // Configure StudentId as FK for StudentAddress 
    modelBuilder.Entity<Student>() 
       .HasRequired(s => s.Address) 
       .WithRequiredPrincipal(ad => ad.Student); 

} 

En el ejemplo anterior, modelBuilder.Entity(). HasRequired (s => s.Address) hace que se requiere la propiedad Dirección de StudentAddress. .WithRequiredPrincipal (ad => ad.Student) crea la propiedad del Estudiante de la entidad StudentAddress según sea necesario. Por lo tanto, configura ambos extremos requeridos. Así que ahora, cuando intentes guardar la entidad Student sin dirección o entidad StudentAddress sin Estudiante, arrojará una excepción.

Referencia: http://www.entityframeworktutorial.net/code-first/configure-one-to-one-relationship-in-code-first.aspx

Cuestiones relacionadas