2010-09-01 8 views

Antwort

11

Sind Sie auf der Suche nach so etwas?

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: Ja, ich habe VS nicht vor mir, aber Sie müssen die folgende Zeile in den UserMapping anstelle der aktuellen HasRequired hinzuzufügen und auch hinzufügen ProfileId Eigenschaft (statt Profile_Id, dass Sie hinzugefügt):

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

ich glaube nicht, dass derzeit rund dies ein Weg, es gibt, aber ich bin sicher, dass es da wir nur in CTP4 sind ändern. Es wäre schön, wenn ich sagen könnte:

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

Auf diese Weise würde ich nicht eine ProfileId Unterkunft zählen müssen. Vielleicht gibt es momentan einen Weg, und es ist noch früh am Morgen, dass ich denke :).

Denken Sie auch daran, .Include("Profile") aufzurufen, wenn Sie eine "Navigationseigenschaft" einschließen möchten.

+0

Funktioniert das für Sie? Ich kann es nicht zur Arbeit bringen. Ich erzeuge die Datenbank nicht automatisch, da ich bereits existierende Tabellen habe. Meine Profiltabelle hat Id als PK und FK (wie die Beziehung 1: 1 ist). Ich nehme an, dass dies das gleiche ist wie du. Wenn ich versuche, Ihren Code auszuführen, erhalte ich einen Fehler: Ungültiger Spaltenname 'Profile_Id'. Wenn ich diese Spalte zu Benutzer hinzufügen (nicht, dass ich es dort möchte), Benutzer wird zurückgegeben, aber Profil ist null. Die SQL erzeugt wird. SELECT [Extent1] [Id] AS [Id], [Extent1] [Benutzername] AS [Benutzername], [Extent1] [profile_id] AS [profile_id] FROM [DBO.. ]. [Benutzer] AS [Extent1] Irgendwelche Ideen? –

+0

hmm. Bei der zweiten Inspektion sieht das auf sqlce4, aber nicht auf sql server 2010 gut aus, es sei denn, mir fehlt etwas. –

+1

@ zaph0d - Wenn Sie auf eine Eigenschaft zugreifen möchten, die "eine andere Entität" ist, müssen Sie sie "einschließen". Der Weg dazu wäre 'context.Users.Include (" Profile ")'. Profil ist eine "Navigationseigenschaft", die einen JOIN in SQL erfordert. Ich habe meinen Beitrag mit dem Extra an Informationen, die ich für das Profil vergessen habe, bearbeitet. – 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; } 
} 

Fügen Sie das virtuelle Profil und die UserID hinzu und ich denke, das sollte Sie dorthin bringen.

+2

Wäre das nicht eine eins zu viele Beziehung? Die Frage war etwa 1: 1. – saille

+0

Nein, ist es nicht. es ist 1: 1 Ein Benutzer hat 1 Profil in diesem Beispiel ... Wenn nicht, habe ich etwas komplett missverstanden. – BjarkeCK

22

drei Methoden:

A) erklären beide Klassen mit Navigationseigenschaften zueinander. Markieren Sie eine der Tabellen (die abhängige Tabelle) mit dem ForeignKey-Attribut für den Primärschlüssel. EF folgert 1-zu-1 von diesem.

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

ich nicht virtual nicht genutzt haben, und Sie sollten auch nicht *

B) Deklarieren Sie eine Vererbungshierarchie mit beiden Tabellennamen explizit angegeben, was zu Table-Per-Type und einem gemeinsamen Primärschlüssel führt.

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

Sie erhalten 2 Tabellen: Eine für AppUser, eine für AdminUser. AdminUser ist 1: 1 mit AppUser und ist abhängig - was bedeutet, dass Sie einen AdminUser löschen können. Wenn Sie jedoch einen AppUser löschen, während ein AdminUser immer noch darauf zeigt, erhalten Sie einen Constraint Violation Error.

C) Es gibt 2 auf halben Weg Methoden der Eins-zu-eins in EF tun:

Entity-Splitting, wo Sie eine einzelne Klasse haben, aber es ist in einer primären Tabelle gespeichert, und 1 oder mehr eins zu eins verwandte Tabellen.

Table-Splitting, wo ein Baum von Objekten in einer einzigen Tabelle flacht. Zum Beispiel würde eine Klasse mit einer Address-Eigenschaft Spalten für das Address-Objekt, wie Address_City, in einer einzigen Tabelle abgeflacht haben.

* Sie können virtuelle Dateien in beliebige EF-Eigenschaften oder Sammlungen einschließen if you want to lazy-load them. Dies kann zu Endlosschleifen oder dem Laden der gesamten Datenbank führen, wenn Sie ein Objekt mit Lazy-Loaded-Eigenschaften beispielsweise an den MVC JSON-Konverter oder an andere Objekte übergeben, die die Objekthierarchie durchlaufen. Das Lazy-Loading wird immer synchron ausgeführt, blockiert den Thread und ohne vorherige Benachrichtigung. Zusammenfassend ist die Liste der Möglichkeiten, wie Sie Ihren Code, Ihre App oder Ihren Server damit einfrieren können, lang. Vermeiden Sie die Verwendung virtueller EF-Klassen. Ja, es gibt eine Menge Code-Beispiele im Internet, die es verwenden. Nein, du solltest es immer noch nicht benutzen.

+0

warum nicht verwenden "virtuelles" Stichwort – AminM

+0

@AminM Siehe die Notiz am Ende über Lazy-Loading und virtuelle. –

1

Nehmen Sie ein Beispiel für die folgenden Entitäten Student und StudentAddress.
Konfigurieren einer Eins-zu-Null-oder-eins-Beziehung mit 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; } 
} 

Wenn StudentAddress Einheit folgt nicht Konventionen:

Wenn zum Beispiel nicht StudentAddress Einheit des nicht folgen Konvention für PK, dh ein anderer Name für die Id-Eigenschaft, dann müssen Sie es auch für PK konfigurieren. Stellen Sie sich die folgende StudentAddress-Entität vor, die den Namen StudentId anstelle von StudentAddressId hat.

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

Im obigen Beispiel müssen wir StudentID Eigenschaft als Key sowie ForeignKey konfigurieren. Dadurch wird die StudentId-Eigenschaft in der StudentAddress-Entität als PK und FK definiert.

konfigurieren One-to-Zero-oder-eins-Beziehung mit Fluent API:
Wenn Schüler und StudentAddress die Konventionen folgen: Studenten und StudentAddress Einheiten folgen Sie den Standardcode-first-Konvention für PrimaryKey. Also müssen wir sie nicht konfigurieren, um ihre Primärschlüssel zu definieren. Wir müssen nur die Entität StudentAddress konfigurieren, in der StudentAddressId ForeignKey sein sollte.

Im folgenden Beispiel wird eine Beziehung zwischen Eins und Null oder eine Beziehung zwischen Student und StudentAddress mithilfe der Fluent-API festgelegt.

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 

} 

In dem obigen Beispiel wird unter Verwendung von Studenten Entität HasOptional() Methode ausgebildet, die die StudentAddress Navigationseigenschaft in Studenten Einheit anzeigt, dass ein optional (nicht erforderlich, wenn Schüler Entität Speicher) ist. Anschließend konfiguriert die WithRequired() -Methode die StudentAddress-Entität und setzt die Student-Navigationseigenschaft von StudentAddress wie erforderlich (erforderlich beim Speichern der StudentAddress-Entität. Es wird eine Ausnahme ausgelöst, wenn die StudentAddress-Entität ohne die Navigationseigenschaft Student speichert). Dies macht StudentAddressId auch als ForeignKey.

So können Sie eine Eins-zu-Null-Beziehung zwischen zwei Entitäten konfigurieren, für die Student-Entität gespeichert werden kann, ohne dass das StudentAddress-Objekt angehängt wird. StudentAddress-Entität kann jedoch nicht ohne Anhängen eines Objekts der Student-Entität gespeichert werden. Dies macht ein Ende erforderlich.

Wenn StudentAddress Einheit Konventionen nicht folgen:
Nun lassen Sie uns ein Beispiel für StudentAddress Einheit nehmen, wo es nicht Primärschlüssel Konvention heißt unterschiedliche Id Eigenschaftsnamen als Id folgt. Betrachten Sie die folgenden Entitäten Student und 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; } 
} 

So, jetzt brauchen wir StudentID Eigentum von StudentAddress für PrimaryKey von StudentAddress sowie ForeignKey wie unten gezeigt zu konfigurieren.

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

} 

konfigurieren One-to-One-Beziehung mit Fluent API:
Wir Eins-zu-Eins-Beziehung zwischen Entitäten Fluent API konfigurieren können, wo beide Enden erforderlich sind, Studenten Entitätsobjekt Sinn muss StudentAddress Einheit umfassen Objekt und StudentAddress-Entität muss Student-Entitätsobjekt enthalten, um es zu speichern.

Hinweis: Eine Eins-zu-Eins-Beziehung ist in MS SQL Server technisch nicht möglich. Es wird immer eins zu null oder eins sein. EF bildet Eins-zu-Eins-Beziehungen für Entitäten, die nicht in DB sind.

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

} 

In dem obigen Beispiel modelBuilder.Entity(). HasRequired (s => s.Address) macht Adresse Eigenschaft StudentAddress erforderlich ist. .WithRequiredPrincipal (ad => ad.Student) macht die Student-Eigenschaft der Entität StudentAddress wie erforderlich. So konfiguriert er beide Enden benötigt. Wenn Sie nun versuchen, die Entität Student ohne Adresse oder die Entität StudentAddress ohne Student zu speichern, wird eine Ausnahme ausgelöst.

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

Verwandte Themen