View Model w ASP.NET MVC

View Model - model danych na potrzeby widoku.


View model to klasa modelu tworzona na potrzeby widoku. Załóżmy, że mamy listę ofert dodawanych przez użytkowników i chcemy na liście z ofertami przejazdów wyświetlić również podstawowe informacje o dodającym. W takim przypadku w bazie danych posiadamy 2 tabele (kurs i user) połączone relacjami. Do widoku możemy przekazać tylko jeden model domenowy a więc model z klasą kurs lub klasą user (każda tabela posiada własną klasę z modelem). W takiej sytuacji niezbędne jest stworzenie klasy KursUserViewModel łączącej potrzebne dane z klasy kurs i klasy user. Klasa ViewModel nie zawiera wszystkich pól jakie są dostępne w klasach które łączy, powinna zawierać tylko te dane które są potrzebne do widoku. Klasa ViewModel nie koniecznie musi łączyć kilka tabel z bazy danych, może również obejmować tylko cześć pół, z podstawowego modelu, np. tylko imie i nazwisko, gdzie w tabeli istnieje 15 różnych pół. Dla klas ViewModel należy określić reguły walidacji podobnie jak dla zwykłych klas z modelem.

Przykładowy kod klasy kurs:

[Bind(Exclude = "DataDodania")]
    [Table("Kurs", Schema = "dbo")]
    public partial class Kurs
    {
        public Kurs()
        {
        this.KursUser = new HashSet<KursUser>();
        }
 
        [Key]
        [ScaffoldColumn(false)]
        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
 
        [DisplayName("Osoba prywatna:")]
        public bool Typ { get; set; }
 
        [Required]
        [DisplayName("Z:")]
        public string Skad { get; set; }
 
        [Required]
        [DisplayName("Do:")]
        public string Dokad { get; set; }
 
        [DataType(DataType.Date)]
        [DisplayName("Kiedy:")]
        public System.DateTime DataWyjazdu { get; set; }
        
        [DataType(DataType.Date)]
        [DisplayName("Data dodania:")]
        [ScaffoldColumn(false)]
        public System.DateTime DataDodania { get; set; }
 
        public virtual ICollection<KursUser> KursUser { get; set; }
    }

Kod klasy user:

[Bind(Exclude = "DataRej")]
[Table("UserProfile", Schema = "st_szukam")]
public class UserProfile
{
    public UserProfile()
    {
        this.KursUser = new HashSet<KursUser>();
    }
 
    [Key]
    [ScaffoldColumn(false)]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }
 
    [EmailAddress]
    [DisplayName("Nazwa Użytkownika:")]
    public string UserName { get; set; }
        
    [Phone]
    [DisplayName("Telefon:")]
    public string Telefon { get; set; }
 
    [DisplayName("Data Rejestracji:")]
    [ScaffoldColumn(false)]
    public System.DateTime DataRej{ get; set; }
    
    public virtual ICollection<KursUser> KursUser { get; set; }
}

Kod klasy KursUserViewModel:

public class KursUserViewModel
{
    [EmailAddress]
    [DisplayName("Nazwa Użytkownika:")]
    public string UserName { get; set; }
 
    [Required]
    [DisplayName("Z:")]
    public string Skad { get; set; }
 
    [Required]
    [DisplayName("Do:")]
    public string Dokad { get; set; }
 
    [DataType(DataType.Date)]
    [DisplayName("Kiedy:")]
    public System.DateTime DataWyjazdu { get; set; }
}
Powyższa klasa łączy tylko niektóre pola z dwóch poprzednich klas. W tym przypadku klasy nie są na tyle rozbudowane, aby była konieczność wybiórczego pobierania określonych pól. Dlatego wykorzystamy tutaj inne podejście. Klasa KursUserViewModel będzie łączyć wszystkie pola z jednej i drugiej klasy. W tym celu ViewModel poprostu będzie składał z dwóch poprzednich modeli domenowych a więc Kurs i User.

Kod klasy KursUserViewModel łączącej 2 klasy:

public class KursUserViewModel
{
    public Kurs kurs { get; set; }
    public UserProfile user { get; set; }
}

Pobieranie danych do ViewModelu:

public IQueryable<Kurs> GetLast(int naStrone, int strona)
{
    return _db.Set<Kurs>().OrderByDescending(x => x.DataDodania).Skip(naStrone * 
					(strona-1)).Take(naStrone);
}
 
public IList<KursUserViewModel> GetKursUserViewList(int naStrone, int strona)
{
    List<KursUserViewModel> lista = new List<KursUserViewModel>();
    IList<Kurs> kursy = GetLast(naStrone, strona).ToList<Kurs>();
    foreach (var k in kursy)
    {
        KursUserViewModel vm = new KursUserViewModel();
        vm.kurs = k;
        vm.user = (from u in _db.Set<UserProfile>()
                        join c in _db.Set<KursUser>() on u.UserId equals c.UserId
                        where c.KursId == k.Id
                        select u).FirstOrDefault();   
        lista.Add(vm);
    }
    return lista;
}
Aby pobrać dane do ViewModelu musimy pobrać listę interesujących nas kursów. Kursy pobieramy przy pomocy metody pomocniczej GetLast(). Po pobraniu kursów, w pętli foreach dla każdego kursu, pobieramy odpowiadającego mu użytkownika i dodajemy do listy obiektów dla naszego ViewModelu.

Kod widoku dla stworzonego ViewModelu:

@model IEnumerable
 
@{
    ViewBag.Title = "Lista ofert";
}
 
<h2>Lista ofert</h2>
 
<p>
    @Html.ActionLink("Dodaj nową tasę", "Dodaj")
</p>
<table>
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.user.UserName)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.kurs.Skad)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.kurs.Dokad)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.kurs.DataWyjazdu)
        </th>
    </tr>
 
@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.user.UserName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.kurs.Skad)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.kurs.Dokad)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.kurs.DataWyjazdu)
        </td>
    </tr>
}
 
</table>
Komentarze facebook (polub nasz profil na FB aby je zobaczyć):