5
public class Order 
{ 
public int Id {get;set;} 
[DisplayName("User")] 
public long UserId { get; set; } 
[ForeignKey("UserId")] 
public virtual User User { get; set; } 
public decimal Amount { get; set; } 
} 

Z IEnumurableKiedy odsłonić IEnumerable zamiast ICollection?

public class User 
{ 
public int Id{get;set;} 
public virtual IEnumerable<Order> Orders { get; set; } 
} 

public User GetWithOrders() 
{ 
var myUser=UserRepository.GetByEmail("[email protected]"); 
myUser.Orders=OrderRepository.GetByUserId(myUser.Id); 
return myUser; 
} 

Z ICollection

public class User 
{ 
public int Id{get;set;} 
public virtual ICollection<Order> Orders { get; set; } 
} 

public User GetWithOrders() 
{ 
var myUser=UserRepository.GetByEmail("[email protected]"); 
return myUser; 
} 

nie mam leniwy załadunku przy użyciu IEnumerable dla właściwości nawigacji. Dlatego muszę uzyskać zamówienia dla tego użytkownika z innym zapytaniem.

Mam nawigację z ICollection. Dzięki temu mogę uzyskiwać zamówienia od użytkownika. To wydaje się fajne. Ale potem mogę dodawać nowe zamówienia do użytkownika w kontrolerze bez korzystania z usługi lub repozytorium.

To rodzaj manipulowania danymi na poziomie kontrolera. Czy to anty-wzór?

Odpowiedz

2

Ale [z ICollection] Mogę dodać nowe zamówienie w kontrolerze bez korzystania z usługi lub repozytorium.

To znaczy, można to zrobić (zakładając, że nie ma ViewModel dodawania rozkaz użytkownika i SaveChanges() gdzieś):

public class UserController 
{ 
    public ActionResult AddUserOrder(AddUserOrderModel addOrder) 
    { 
     User user = User.GetByEmail(addOrder.UserEmail);   
     user.Orders.Add(addOrder.Order); 
     User.SaveChanges(); 
    } 
} 

A zwłaszcza, że ​​można zrobić user.Orders.Add(...), to jest to efekt uboczny eksponowania typów jednostek z warstwy usługi lub repozytorium.

Jeśli chcesz tego uniknąć, trzeba by zdefiniować i wystawiać obiekt biznesowy zawierający elementy, które chcesz wystawiać:

public class UserBLL 
{ 
    public int Id { get; private set; } 
    public IEnumerable<Order> Orders { get { return _orders.AsEnumerable(); } } 
    private IEnumerable<Order> _orders; 

    public UserBLL(User user) 
    { 
     Id = user.Id; 
     _orders = user.Orders;   
    } 

    public void AddOrder(Order order) 
    { 
     _orders.Add(order); 
    } 
} 
+0

Po pierwsze myślałem również o viewmodelu. Ale nie byłem pewien, czy może to przynieść więcej komplikacji, czy nie. Użyję viewmodels, jeśli będę musiał. Dzięki. –

+0

Punkt nie jest naprawdę modelem widoku. To BLL lub model domeny. Obiekty reprezentujące Twój przypadek użycia (Użytkownik, który może mieć Zamówienia). Użyj tego, jeśli nie chcesz wystawiać swoich modeli danych z odsłoniętymi wnętrznościami. – CodeCaster

+0

Dlaczego zwracasz '_orders.AsEnumerable();' podczas gdy '_orders' jest już' IEnumerable '? –

1

Nie ma tu prawdziwego wyboru. ICollection jest potrzebny EF do kontrolowania niektórych jego aspektów, takich jak wiążące wyniki zapytań i leniwe ładowanie. Używając IEnumerable, zasadniczo wyłączasz tę funkcjonalność, ale wraz z nią zrozumienie przez EF struktury bazowej. Podczas generowania migracji EF nie wygeneruje żadnych wymaganych bazowych tabel łączenia dla relacji M2M, kluczy obcych w powiązanych tabelach itp.

Długie i krótkie, należy użyć ICollection. Chociaż masz rację, to pozwala dodawać elementy, po prostu dodając je do kolekcji w pokrewnym elemencie, sans-DAL, nadal nie mogą być one zapisane, bez dostępu do kontekstu. Jeśli poprawnie skonfigurowałeś DAL, to jest on dostępny tylko przez DAL, więc nadal musisz przekazać go z powrotem do swojego potoku DAL, aby utrwalić którąkolwiek z tych zmian. Innymi słowy, nie przejmuj się tym.

+0

używam MKOl. Kontekst udostępniany na żądanie. W tej samej prośbie, jeśli zgłosiłem to w innym celu, może to mieć wpływ. Ale masz rację Myślę, że nie mam żadnej akcji, która wybrałaby zapytanie relacyjne, a następnie zapisz lub edytuj na tym samym żądaniu. Jeśli mam, użyję viewmodel, który powiedział @CodeCaster. –