2016-08-15 23 views
8

To jest coś, co podsłuchiwało mnie od czasu przejścia na EF 6. W jaki sposób teraz mapujemy kolekcje, aby zobaczyć modele takie, że cofanie mapowania nie jest bolesne przy użyciu IEnumerables. Oto fragment kodu poniżej wykazania mój problem:Odwzorowywanie elementów EF na ViewModels z zachowaniem ICollection i leniwym ładowaniem

Entity - SS.Entity.Event

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] 
public virtual ICollection<SS.Entity.User> Broadcasters { get; set; } 
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] 
public virtual ICollection<SS.Entity.User> Viewers { get; set; } 

model - SS.Model.Event

public virtual ICollection<SS.Model.User> Broadcasters { get; set; } 
public virtual ICollection<SS.Model.User> Viewers { get; set; } 

Powrót do mapowania Entity Po modyfikacji kolekcji

Broadcasters = e.Broadcasters.Select(u => new SS.Entity.User 
{ 
    Id = u.Id, 
    SkypeId = u.SkypeId, 
    Name = u.Name 
}).ToList(), // THIS IS THE PROBLEM 
Viewers = e.Viewers.Select(u => new SS.Entity.User 
{ 
    Id = u.Id, 
    SkypeId = u.SkypeId, 
    Name = u.Name 
}).ToList() // THIS IS THE PROBLEM 

Problem polega na tym, że nie mogę zmapować ICollection do innej ICollection, ponieważ Select tworzy IEnumerable, który odwzorowuje właściwości z powrotem na EF, po czym pojawia się ból, ponieważ muszę odtworzyć kolekcję lub wyliczyć ją, aby ją zaktualizować. Wiem, że brakuje mi czegoś oczywistego, zaktualizowałem ICollection tak, aby było wirtualne, jak to opisano w innych odpowiedziach, ale nie jest dla mnie jasne, jak to pomaga.

Każda pomoc będzie bardzo ceniona!

Gerard

+0

Dlaczego nie 'Nadawcy = e.Broadcasters'? To bardzo niejasne, o co prosisz. Czy istnieje jedna klasa "User" lub dwie? I w jaki sposób jest to związane z leniwym ładowaniem? –

+0

Próbowałem uczynić jaśniejszym poprzez dodanie przestrzeni nazw. Zasadniczo moje pytanie brzmi: jak odwzorować zmiany kolekcji w EF6. Nie widzę żadnego wyraźnego sposobu, aby to zrobić bez ToList(). W związku z tym występuje znaczny spadek wydajności podczas pracy z dużymi kolekcjami. –

+0

"... kolekcje map do przeglądania modeli takich, że cofanie mapowania nie jest bolesne przy użyciu IEnumerables" ..... to nie jest jasne. Co masz na myśli przez "kolekcje map przez". Jak pokazano w Twoim poście, tworzysz nowe typy ze swoich DTO ... Dlaczego to nie działa? – Sam

Odpowiedz

1

Na ViewModel, mogą być po prostu IEnumerable<T>, chyba że trzeba robić .Add() na nich później. To może być cokolwiek chcesz być. Ponadto nie muszą być wirtualne w modelu, ponieważ nie masz EF, aby utworzyć model pochodny modelu (ponownie, chyba że masz inny powód).

Aby ustawić je z powrotem w obiektach DTO, jeśli chcesz je ustawić bezpośrednio, a nie sprawdzić poszczególnych właściwości, możesz użyć parametru .ToList(), aby spełnić wymóg ICollection<T>.

// Assuming "var model" is coming in as a parameter 
var station = context.Viewers.First(); 
station.Broadcasters = model.Broadcasters.Select(b => new User { 
    Id = b.Id, 
    SkypeId = b.SkypeId, 
    Name = b.Name 
}).ToList(); 
station.Viewers = model.Viewers.Select(v => new User { 
    Id = v.Id, 
    SkypeId = v.SkypeId, 
    Name = v.Name 
}); 
+0

To działało w wersjach przed EF6, ale już nie działa. Tworzenie instancji nowych obiektów nawet do odwzorowania powoduje utworzenie nowych jednostek dla każdej aktualizacji, a nie tylko aktualizację kolekcji. –

+0

Również ToList() wylicza kolekcję, która, jeśli ta kolekcja jest ogromna, powoduje problemy z wydajnością. –

+0

Kolekcja będzie iterowana, bez względu na wszystko. Co najmniej twoje pytanie jest bardzo niejasne, co do twojego zestawu problemów. Co się teraz dzieje z EF6, co nie działo się w EF5? – krillgar

2

Zakładając, że ".ToList()" kwestią jest natomiast zapisywanie z powrotem do bazy, czy to co się szuka ?:

var event = new SS.Entity.Event {Name = "New Name" and other properties}; 

IEnumerable<SS.Entity.User> broadcasters = e.Broadcasters 
     .Select(u => new SS.Entity.User 
      { 
       Id = u.Id, 
       SkypeId = u.SkypeId, 
       Name = u.Name 
      }); 

var viewers = e.Viewers.Select(u => 
      new SS.Entity.User 
      { 
      Id = u.Id, 
      SkypeId = u.SkypeId, 
       Name = u.Name 
      }); 

//add broadcasters to event 
event.Broadcasters.AddRange(broadcasters); 

//add viewers to event 
event.Viewers.AddRange(viewers); 

dataContext.Events.Add(event); 
dataContext.SaveChanges(); 
+0

To jest dobry pomysł ... Nie mam dostępu do kodu w tej chwili, aby go wypróbować, ale pozwól mi rzucić okiem na jutro. Czy dodany zakres zajmuje IEnumerable? –

+0

@Gerard - tak, robi. https://msdn.microsoft.com/en-us/library/system.data.entity.dbset.addrange(vsv13.1).aspx – Developer

+0

@GerardWilkinson przy odrobinie szczęścia? – Developer