2012-10-20 9 views
6

Znalazłem wiele podobnych pytań tutaj, ale żaden z nich nie wydaje mi się pomóc w moim problemie. Atrybuty fluent api & nie pomogły. Baza danych została utworzona, ale po dodaniu do niej obiektu uległa awarii. Chcę mieć klasę, która ma własną kolekcję. Oto kod mam:Code First - Odwoływanie się jedna do wielu relacji

[Table("UObjects")] 
public class UObject 
{ 
    [Key] 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    [Browsable(false)] 
    public long ID { get; set; } 
    public string Name { get; set; } 
    [Browsable(false)] 
    public long? ParentID { get; set; } 

    public virtual UObject UParent { get; set; } 
    [Browsable(false)] 
    public virtual ICollection<UObject> UObjects { get; set; } 
} 


public class MyContext : DbContext 
{ 
    public DbSet<UObject> UObjects { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     // This fluent API didn't help 
     //modelBuilder.Entity<UObject>() 
     //  .HasOptional(u => u.UParent) 
     //  .WithMany(u => u.UObjects) 
     //  .HasForeignKey(u => u.ParentID); 

     //modelBuilder.Entity<UObject>() 
     //  .HasOptional(u => u.UParent) 
     //  .WithMany(u => u.UObjects) 
     //  .Map(c => 
     //  { 
     //   c.MapKey("ParentID"); 
     //   c.ToTable("UObjects"); 
     //  }); 
    } 
} 

Zapisy w bazie danych to tak:

ID | Name  | ParentID 
------------------------------------ 
1 | First  | 0 
2 | SubFirst | 1 
3 | SubSecond | 1 
4 | SubThird | 2 
5 | SubFourth | 2 

Więc jak mój obiekt powinien wyglądać po załadowaniu podmiotów jest następny:

- First 
     - SubFirst 
     - SubThird 
     - SubFourth 
     - SubSecond 

Ale każdy przedmiot ma pustą kolekcję. Co powinienem zrobić, aby działał poprawnie?

+0

Sprawdź to http://stackoverflow.com/questions/10421351/many-to-many-relationship-between-entities-of-same-type-in-mvc3/10422172#10422172 – Shyju

+0

próbowałem już. Stworzył bazę danych, ale zawiesza się podczas dodawania nowego obiektu i wywoływania SaveChanges() – GaaRa

+5

"* to rozbił *" nie jest tak naprawdę dobrym opisem problemu. 1) Czym dokładnie jest wyjątek? 2) Jakie zapytanie uruchomiłeś, gdy załadowałeś encje z pustymi kolekcjami? 3) Dlaczego masz 'ParentID' z' 0' w pierwszym rzędzie bazy danych? Narusza więzy referencyjne (nie ma wiersza z 'ID' 0). Czy masz na myśli 'NULL'? – Slauma

Odpowiedz

-3
  1. Udekoruj swoją właściwość UParent za pomocą ForeignKey Attribute i? ponieważ może być pustych

[ForeignKey("ParentID")] public virtual UObject? UParent { get; set; }

  1. W bazie: Ustaw wartość parentId do 'null' jeśli nie ma rodzica.
+2

? jest niepoprawny, ponieważ UObject jest klasą, a nie typem wartości. –

5

Wystarczy tylko wspomnieć odniesienie siebie poprzez korygowanie na polu, a nie na nawigacji właściwość tak:

[ForeignKey("UParent")] // EF need for self reference 
public long? ParentID { get; set; } 

A w konstruktorze zainicjować właściwości nawigacyjnych tak:

public UObject()  
    { 
     // this is necessary otherwise EF will throw null object reference error. you could also put ?? operator check for more interactive solution. 
     UObjects = new List<UObject>(); 
    } 

I również musisz nadpisać, jak to robiłeś, ale w ten sposób:

protected override void OnModelCreating(DbModelBuilder modelBuilder)  
    { 
     // folowwing is also necessary in case you're using identity model  
     base.OnModelCreating(modelBuilder);    
     modelBuilder.Entity<UObjects>()  
      .HasOptional<UObjects>(u => u.UParent) // EF'll load Parent if any  
      .WithMany(u => u.UObjects);  // load all childs if any 
    } 
+0

Osiągam to samo zachowanie dla kategorii i podkategorii oraz w wielu miejscach, w których wymagane jest samo odniesienie. Prosimy nie krępować się, jeśli wciąż nie uzyskać pożądanych rezultatów. –

+0

Inicjowanie kolekcji w konstruktorze nie jest konieczne. EF utworzy go, gdy będzie puste. –

1

Klasa jednostek prawie identyczna z twoją pracuje w EF Core. Zmieniono nazwę Twojej nieruchomości ParentID na UParentID i dodano konstruktory.

[Table("UObjects")] 
public class UObject 
{ 
    protected UObject() 
    { 
    UObjects = new List<UObject>(); 
    } 

    public UObject(UObject parent, string name) 
    : this() 
    { 
    Name = name; 
    UParent = parent; 
    UParent?.UObjects.Add(this); 
    } 

    [Key] 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public long ID { get; set; } 
    public string Name { get; set; } 
    public long? UParentID { get; set; } 

    public virtual UObject UParent { get; set; } 
    public virtual ICollection<UObject> UObjects { get; set; } 
} 

W ApplicationDBContext mam tylko to:

protected override void OnModelCreating(ModelBuilder builder) 
{ 
    base.OnModelCreating(builder); 
    builder.Entity<UObject>(); 
} 

Usage (Patrz Jak właściwości obiektu root wypełnione są prawidłowe wartości): Eager loading

Uwaga: Nie kłopotać się usunięciem tego kodu. Jeśli jej potrzebujesz, rzeczy prawdopodobnie będą bardziej skomplikowane.

Powiązane problemy