2010-09-01 11 views

risposta

11

Stai cercando qualcosa di simile?

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); 
    } 
} 

EDIT: Già non ho avuto VS di fronte a me, ma è necessario aggiungere la seguente riga nel UserMapping invece degli attuali HasRequired e anche aggiungere una proprietà ProfileId (invece di Profile_Id che si aggiunto):

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

io attualmente non credo che ci sia un modo per aggirare questo, ma sono sicuro che cambierà dal momento che siamo solo in CTP4. Sarebbe bello se potessi dire:

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

In questo modo non avrei dovuto includere una proprietà ProfileId. Forse c'è un modo per aggirare questo attualmente ed è ancora al mattino presto per me pensare :).

Ricordare inoltre di chiamare .Include("Profile") se si desidera includere una "proprietà di navigazione".

+0

Questo funziona per voi? Non riesco a farlo funzionare. Non sto generando il database automaticamente come ho tabelle esistenti. La mia tabella profilo ha Id come PK e FK (poiché la relazione è 1: 1). Suppongo che questo sia uguale a te. Se provo a eseguire il codice, viene visualizzato un messaggio di errore: Nome colonna non valido 'ID profilo'. Se aggiungo quella colonna all'utente (non che lo voglio lì), l'utente viene restituito ma il profilo è nullo. L'SQL generato è:. SELEZIONA [Extent1] [Id] AS [Id], [Extent1] [nome utente] AS [nome utente], [Extent1] [profile_id] AS [profile_id] FROM [dbo.. ]. [Utenti] AS [Extent1] Qualche idea? –

+0

hmm. Alla seconda ispezione, sembra che questo funzioni bene su sqlce4, ma non su SQL Server 2010 a meno che manchi qualcosa. –

+1

@ zaph0d - Se si desidera accedere a una proprietà che è "un'altra entità", è necessario "includerla". Il modo per farlo sarebbe 'context.Users.Include (" Profile ")'. Il profilo è una "proprietà di navigazione" che richiede un JOIN in SQL. Ho modificato il mio post con le informazioni aggiuntive che ho dimenticato per il profilo. – 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; } 
} 

Aggiungere il profilo virtuale e l'ID utente e penso che dovrebbe portarvi lì.

+2

Non sarebbe una relazione uno a molti? La domanda era circa 1: 1. – saille

+0

No, non lo è. è 1: 1 Un utente ha 1 profilo in questo esempio ... Se non ho frainteso qualcosa completamente. – BjarkeCK

22

tre metodi:

a) dichiarare entrambe le classi con proprietà di navigazione gli uni agli altri. Segna una delle tabelle (la tabella dipendente) con l'attributo ForeignKey sulla sua chiave primaria. EF deduce 1-a-1 da questo:.

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

Non ho usato virtual e non si deve neanche *

B) Dichiarare una gerarchia di ereditarietà con entrambi i nomi di tabella esplicitamente dichiarato, risultante in Table-Per-Type e una chiave primaria condivisa.

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; } 
} 

Otterrete 2 tabelle: una per AppUser, una per AdminUser. AdminUser è 1: 1 con AppUser ed è dipendente - il che significa che puoi eliminare un AdminUser, ma se elimini un AppUser quando un AdminUser sta ancora puntando su di esso, otterrai un errore di violazione di vincoli.

C) Ci sono 2 metodi mezza modo di fare uno-a-uno in EF:

Entity-Splitting, dove si ha una sola classe, ma è memorizzati in una tabella primaria e 1 o più tabelle correlate one-to-one.

Table-Splitting, dove un albero di oggetti si appiattisce in un unico tavolo. Ad esempio una classe con una proprietà Address avrebbe colonne per l'oggetto Address, come Address_City, appiattito in una singola tabella.

* È possibile includere virtuale su qualsiasi proprietà EF o raccolte if you want to lazy-load them. Ciò può causare loop infiniti o caricare l'intero DB se si passa un oggetto con proprietà lazy-loaded a, ad esempio, il convertitore JSON MVC o qualsiasi altra cosa che percorre la gerarchia dell'oggetto. Il caricamento pigro viene sempre eseguito in modo sincrono, bloccando il thread e senza preavviso. Per riassumere, l'elenco dei modi in cui è possibile bloccare il codice, l'app o il server con esso è lungo. Evitare l'uso virtuale su classi EF. Sì, ci sono molti esempi di codice su internet che lo usano. No, non dovresti ancora usarlo.

+0

perché non utilizzare la parola chiave "virtuale" – AminM

+0

@AminM Vedere la nota alla fine del caricamento pigro e virtuale. –

1

Prendete un esempio delle seguenti entità Student e StudentAddress.
Configurare uno-a-zero o-uno con 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; } 
} 

Quando StudentAddress entità non segue le convenzioni:

Se, per esempio, StudentAddress entità non segue la convenzione per PK, ovvero nome diverso per la proprietà Id, quindi è necessario configurarlo anche per PK. Si consideri la seguente entità StudentAddress che ha il nome della proprietà StudentId invece di 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; } 
} 

Nell'esempio precedente, è necessario configurare la proprietà StudentId come Chiave e come Chiave Esterna. Ciò renderà la proprietà StudentId nell'entità StudentAddress come PK e FK entrambi.

configurare uno-a-zero-o-One rapporto utilizzando API Fluent:
Quando Student e StudentAddress seguono le convenzioni: entità degli studenti e StudentAddress seguono la convenzione in codice prima di default per PrimaryKey. Quindi, non abbiamo bisogno di configurarli per definire i loro PrimaryKey. Abbiamo solo bisogno di configurare l'entità StudentAddress dove StudentAddressId dovrebbe essere ForeignKey.

L'esempio seguente imposta una relazione uno o zero tra Student e StudentAddress utilizzando l'API Fluent.

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 

} 

Nell'esempio precedente, entità Student è configurato utilizzando il metodo HasOptional(), che indica che la proprietà navigazione StudentAddress nell'entità Student è opzionale (non richiesto quando si salva entità Student). Quindi, il metodo WithRequired() configura l'entità StudentAddress e rende la proprietà di navigazione Studente di StudentAddress come richiesto (richiesta quando si salva l'entità StudentAddress. Genera un'eccezione quando l'entità StudentAddress sta salvando senza la proprietà di navigazione di Student). Ciò renderà StudentAddressId anche ForeignKey.

Pertanto, è possibile configurare una relazione da uno a zero-a-uno tra due entità in cui è possibile salvare l'entità Studente senza associare l'oggetto StudentAddress ma l'entità StudentAddress non può essere salvata senza associare un oggetto dell'entità Studente. Ciò rende necessaria un'estremità.

Quando StudentAddress entità non seguono le convenzioni:
Ora, prendiamo un esempio di StudentAddress entità dove non segue convenzione chiave primaria cioè avere altro nome proprietà Id di Id. Considerare le seguenti entità Student e 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; } 
} 

Così ora, abbiamo bisogno di configurare proprietà StudentID di StudentAddress per PrimaryKey di StudentAddress così come ForeignKey come illustrato di seguito.

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); 

} 

configurare uno-a-uno con API Fluent:
possiamo configurare One-to-One relazione tra le entità utilizzando API perfetto dove sono richieste entrambe le estremità, che significa oggetto entità studente deve prevedere StudentAddress entità l'oggetto e l'entità StudentAddress devono includere l'oggetto entità Studente per poterlo salvare.

Nota: la relazione uno a uno non è tecnicamente possibile in MS SQL Server. Sarà sempre uno-a-zero o uno. EF forma relazioni One-to-One su entità non in 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); 

} 

Nell'esempio precedente, modelBuilder.Entity(). HasRequired (s => s.Address) rende è richiesto proprietà Indirizzo di StudentAddress. .WithRequiredPrincipal (ad => ad.Student) rende la proprietà Student dell'entità StudentAddress come richiesto. Così configura entrambe le estremità richieste. Così ora, quando provi a salvare un'entità Student senza indirizzo o entità StudentAddress senza Studente, genererà un'eccezione.

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

Problemi correlati