IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Diskuze: ASP.NET MVC - Náhled článku

V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.

Aktivity
Avatar
Michal Štěpánek:1.2.2017 10:54

Ahoj, rád bych zobrazil ve výpisu (seznamu) požadavků krátký náhled popisu požadavku (obvykle zakončeno třemi tečkami), ale nevím, jak to správně řešit. Napadlo mě třeba, že bych do DB přidal sloupec, kam by se při uložení požadavku uložil nějaký počet znaků z popisu a ten bych pak ve výpisu zobrazil. Celý popis ještě s dalšími údaji se pak zobrazí jako detail požadavku v jiném View. Ale nepřijde mi to jako nejelegantnější řešení. Přijde mi zbytečné duplikovat (byť jen část) data v různých sloupcích. Mohl by mi někdo prosím poradit, jak to lze udělat lépe?

Odpovědět
1.2.2017 10:54
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
vajkuba1234
Člen
Avatar
Odpovídá na Michal Štěpánek
vajkuba1234:1.2.2017 12:37

Co si treba udelat model, ktery by obsahoval napr.: Id, Title, Description, Content, ..., s tim, ze v description bys mel takovy lehci naznak, o cem clanek je a po kliknuti na "pokracovat" se ti zobrazi cely clanek i s decription a content?

Nahoru Odpovědět
1.2.2017 12:37
No hope, no future, JUST WAR!
Avatar
vajkuba1234
Člen
Avatar
Odpovídá na Michal Štěpánek
vajkuba1234:1.2.2017 12:58

No a nebo si udelat pro Index dotaz, ktery zobrazi pouze urcity pocet znaku a v Detailu zobrazis cely obsah.

Btw. ja pouzivam properties Description a Content.

Editováno 1.2.2017 13:00
Nahoru Odpovědět
1.2.2017 12:58
No hope, no future, JUST WAR!
Avatar
Odpovídá na vajkuba1234
Michal Štěpánek:1.2.2017 13:24

Mě jde o zobrazení třeba prvních 80ti znaků, abych ten seznam nemusel mít "víceřádkový", ale ke každému požadavku by byl výpis jen začátek toho popisu, třeba jako je to tady na ITN... Tak nevím, jak je to nejlepší a nejjednodušší udělat...

Nahoru Odpovědět
1.2.2017 13:24
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
vajkuba1234
Člen
Avatar
Odpovídá na Michal Štěpánek
vajkuba1234:1.2.2017 13:26

Tak vytahnout prvnich 80 znaku asi problem nebude ne? Pomoci linq a Take(). Jinak si klidne udelej dalsi vlastnost a nemusis nic resit.

Nahoru Odpovědět
1.2.2017 13:26
No hope, no future, JUST WAR!
Avatar
Odpovídá na vajkuba1234
Michal Štěpánek:1.2.2017 13:32

Někde jsem našel, že by se to dalo udělat nějak takto:

@Html.DisplayFor(modelItem => item.Text.Substring(0,80))

, ale to háže chybu
Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.

Nahoru Odpovědět
1.2.2017 13:32
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
vajkuba1234
Člen
Avatar
Odpovídá na Michal Štěpánek
vajkuba1234:1.2.2017 13:39

Ja bych si radeji udelal dotazy v controlleru, nez natahnout vse, ale zobrazit jen malinkou cast.

Nahoru Odpovědět
1.2.2017 13:39
No hope, no future, JUST WAR!
Avatar
vajkuba1234
Člen
Avatar
Odpovídá na Michal Štěpánek
vajkuba1234:1.2.2017 13:41

btw.

@Html.DisplayFor(modelItem => item.Text).ToString().SubString(0,80)

?

Nahoru Odpovědět
1.2.2017 13:41
No hope, no future, JUST WAR!
Avatar
Odpovídá na vajkuba1234
Michal Štěpánek:1.2.2017 14:07

To poslední taky háže chybu...
P.S.
proč, když udělám View z modelu (jako výpis/seznam - Index), tak to normálně jde a když to chci udělat z ViewModelu, tak to nejde?

[DatabaseGenerated(DatabaseGeneratedOption.Identity), Key()]
        public int Id { get; set; }
        [Display(Name = "Zadáno")]
        [DisplayFormat(DataFormatString = "{0:dd.MM.yyyy}")]
        public DateTime CreationDate { get; set; }
        [Display(Name = "Text úkolu")]
        [Required(ErrorMessage = "Text úkolu je povinný")]
        [MaxLength()]
        public string Text { get; set; }
        [Display(Name = "Splněno")]
        [DisplayFormat(DataFormatString = "{0:dd.MM.yyyy}")]
        public DateTime? ReleaseDate { get; set; }

To mám v modelu a View pro výpis dat je OK. Když toto překopíruji do ViewModelu a udělám View pro výpis, tak mi to po spuštění řve, že to není IEnumerable či co...

Nahoru Odpovědět
1.2.2017 14:07
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
vajkuba1234
Člen
Avatar
Odpovídá na Michal Štěpánek
vajkuba1234:1.2.2017 14:15

Hod sem screen.

Nahoru Odpovědět
1.2.2017 14:15
No hope, no future, JUST WAR!
Avatar
Odpovídá na vajkuba1234
Michal Štěpánek:1.2.2017 14:20

Tuto chybu to zahlásí

The model item passed into the dictionary is of type 'System.Collec­tions.Generic­.List1[Technician.Models.Proposal]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable1[Technician.Vi­ewModels.Propo­salIndexViewMo­del]'.

takto mám ViewModel

public class ProposalIndexViewModel
    {
        [Key]
        public int Id { get; set; }
        [Display(Name = "Zadáno")]
        [DisplayFormat(DataFormatString = "{0:dd.MM.yyyy}")]
        public DateTime CreationDate { get; set; }
        [Display(Name = "Text úkolu")]
        [Required(ErrorMessage = "Text úkolu je povinný")]
        [MaxLength()]
        public string Text { get; set; }
        [Display(Name = "Splněno")]
        [DisplayFormat(DataFormatString = "{0:dd.MM.yyyy}")]
        public DateTime? ReleaseDate { get; set; }
        public IEnumerable<Proposal> proposal;
    }
Nahoru Odpovědět
1.2.2017 14:20
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
Odpovídá na vajkuba1234
Michal Štěpánek:1.2.2017 14:21

a toto v Controlleru

public ActionResult Index()
        {
            return View(db.Proposals.OrderBy(p=>p.ReleaseDate).ToList());
        }
Nahoru Odpovědět
1.2.2017 14:21
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
vajkuba1234
Člen
Avatar
Odpovídá na Michal Štěpánek
vajkuba1234:1.2.2017 14:46

A mas to spravne namapovane?

Nahoru Odpovědět
1.2.2017 14:46
No hope, no future, JUST WAR!
Avatar
Odpovídá na vajkuba1234
Michal Štěpánek:1.2.2017 14:54

Co tím myslíš "správně namapované"?
Když do toho prvního řádku View dám

@model IEnumerable<Technician.Models.Proposal>

tak je to ok

@model IEnumerable<Technician.ViewModels.ProposalIndexViewModel>

toto hodí výše uvedenou chybu
Schválně jsem ho pro jistotu teď vytvořil znovu (to View) a chyba je tam...
Když dělám Create, Detail... z "ViewModelu", tak je to OK. Jen List musím dělat z "Modelu"

Nahoru Odpovědět
1.2.2017 14:54
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
vajkuba1234
Člen
Avatar
Odpovídá na Michal Štěpánek
vajkuba1234:1.2.2017 14:58

Viewmodel ma slouzit jako DTO, takze musis prevest model na viewmodel (cteni z db) nebo naopak (zapis do db).

Koukni na ty privatni metody dole v controlleru:

https://github.com/vajkuba1234/KVHTO/blob/master/KVHTO/Controllers/InformationController.cs
Nahoru Odpovědět
1.2.2017 14:58
No hope, no future, JUST WAR!
Avatar
Odpovídá na vajkuba1234
Michal Štěpánek:1.2.2017 15:08

Čumim na to jako vrána a moudrej z toho nejsem...
Teď musím jít s dcerou na její koncert, večer to zkusim ještě prozkoumat... Dík za rady

Nahoru Odpovědět
1.2.2017 15:08
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
Odpovídá na Michal Štěpánek
Nikola Sterziková (PaNika):1.2.2017 16:02

Souhlasím s "vajkuba1234". V tom controleru vracíš kolekci objektů typu "Technician.Mo­dels.Proposal" ale view očekává kolekci typu "Technician.Vi­ewModels.Propo­salIndexViewMo­del". Mapování z entity v db na tvůj VieModel musíš udělat ty, buď ručně nebo se často používá knihovna AutoMapper, která pracuje na základě jmenné konvence a provádí automatické mapování podle názvů vlastností. (To znamená, že namapuje ty vlastnosti, které se stejně jmenují v db a v DTO)
Na začátku se nakonfiguruje které páry objektů se na sebe váží a pak v kódu se použije funkce .ProjectTo<>.

// V nějaké inicializační třídě, která se spouští jednou na začátku aplikace se definuje mapování:
Mapper.Initialize(cfg => cfg.CreateMap<DatabazovaEntita, ViewModel>());
// Pak při dotazování do db v modelech např.:
var person= context.Osoby.ProjectTo<MojeZjednodusenaTrida>()
                .Where(x => x.ID== id)
                .FirstOrDefault();

Mapování lze provést i naopak z ViewModelu na databázovou entitu v případě ukládání.
Doporučuji zvážit používání. Knihovna má vyřešeno získávání info i relačních tabulek apod...

 
Nahoru Odpovědět
1.2.2017 16:02
Avatar
Odpovídá na vajkuba1234
Michal Štěpánek:2.2.2017 9:41

Asi jsem tupej, ale ať to čtu jak chci, netuším, jak to mám udělat... Mohl bys mi to zkusit ukázat na mé třídě?

public class Proposal
    {
        [DatabaseGenerated(DatabaseGeneratedOption.Identity), Key()]
        public int Id { get; set; }
        [Display(Name = "Zadáno")]
        [DisplayFormat(DataFormatString = "{0:dd.MM.yyyy}")]
        public DateTime CreationDate { get; set; }
        [Display(Name = "Text úkolu")]
        [Required(ErrorMessage = "Text úkolu je povinný")]
        [MaxLength()]
        public string Text { get; set; }
        [Display(Name = "Splněno")]
        [DisplayFormat(DataFormatString = "{0:dd.MM.yyyy}")]
        public DateTime? ReleaseDate { get; set; }

    }
Nahoru Odpovědět
2.2.2017 9:41
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
vajkuba1234
Člen
Avatar
Odpovídá na Michal Štěpánek
vajkuba1234:2.2.2017 10:01
public ActionResult Index()
        {
            //Select data which is visible (Where)
            var tvaKolekce = db.Proposals.OrderBy(p=>p.ReleaseDate);

            var list = MapModelsToViewModel(tvaKolekce, new List<TvujViewModel>());

            return View(list);
        }
private List<PubListInformationViewModel> MapModelsToViewModel(IQueryable<TvujModel> models,
                                                List<TvujViewModel> viewModels)
        {
            foreach (TvujModel i in models)
            {
                viewModels.Add(new TvujViewModel
                {
                    IdInformation = i.Id,
                    TitleInformation = i.Title,
                    DescriptionInformation = i.Description,
                    DateCreatedInformation = i.DateCreated,
                    DateEventInformation = i.DateEvent,
                    Category = i.Category,
                    IdCategory = i.IdCategory
                });
            }
            return viewModels;
        }

Koukni na tu privatni mapovaci metodu... Uz z ni vidis, ze defacto prekopirujes data z modelu do tveho viewmodelu, tady se jedna o vypis z db do stranky. Metoda prijima IQueryable, coz je typ, ktery ti vraci linq dotaz a prevedes si to na seznam viewmodelu. Ty kolekce jsou tam proto, ze v Indexu vypisujes vetsinou nejaky seznam neceho (clanku treba). Ty properties si doufam dokazes predstavit v tom foreachi, takze jsem je neprepisoval.

Akceptované řešení
+20 Zkušeností
+2,50 Kč
Řešení problému
Nahoru Odpovědět
2.2.2017 10:01
No hope, no future, JUST WAR!
Avatar
vajkuba1234
Člen
Avatar
Odpovídá na Michal Štěpánek
vajkuba1234:2.2.2017 10:03

Treba tady to mas taky vysvetlene, mozna asi i lepe. Mas tam jak manualni mapovani v controlleru, tak jak to mam ja, a nebo za pouziti AutoMapperu. Akorat, ze ja to nemam v ActionResult, ale udelal jsem si pro to pomocne metody, at ten controller vypada trochu citelne.

Link:

https://www.mikesdotnetting.com/article/188/view-model-design-and-use-in-razor-views
Nahoru Odpovědět
2.2.2017 10:03
No hope, no future, JUST WAR!
Avatar
vajkuba1234
Člen
Avatar
Odpovídá na Michal Štěpánek
vajkuba1234:2.2.2017 10:30

Jen jeste abys vedel, kdyz kouknes na to mapovani z modelu na VM, tak prave tam si zvolis, ktere property chces zobrazit ve view. Tzn. kdyz ti bude stacit jen Title a Description, tak si das do VM Id, Title a Description a prave v controlleru to namapujes pomoci Automapperu nebo jako treba ja:

IdInformation = i.Id,
TitleInformation = i.Title,
DescriptionInformation = i.Description,

Diky tomu do view posilas pouze to co skutecne potrebujes. Proto jsem ti treba i psal, at si udelas dalsi propertu Description na nejaky kratky popis o co v clanku pujde. Nemusis tam rvat dalsi data, kdyz je stejne potrebovat nebudes a zobrazis je az tehdy, kdy jsou potreba, tedy v detailu. Protoze si treba predstav, ze budes mit model s Id, Content, Galerie a ja nevim co jeste a ty vytahnes vse, zobrazis akorat prvnich 80 znaku z Contentu no a zbytek jsi tahal zbytecne.

Editováno 2.2.2017 10:32
Nahoru Odpovědět
2.2.2017 10:30
No hope, no future, JUST WAR!
Avatar
Odpovídá na vajkuba1234
Michal Štěpánek:2.2.2017 12:48

Jseš husteeej... Dííík

Nahoru Odpovědět
2.2.2017 12:48
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
vajkuba1234
Člen
Avatar
Nahoru Odpovědět
2.2.2017 12:49
No hope, no future, JUST WAR!
Avatar
Odpovídá na vajkuba1234
Michal Štěpánek:2.2.2017 12:57

Nakonec jsem to spáchal takto

private List<ProposalViewModel> MapModelsToViewModel(IQueryable<Proposal> models, List<ProposalViewModel> viewModels)
        {
            foreach (Proposal i in models)
            {
                //zobrazení části popisu
                string nahled = i.Text;
                if(nahled.Length > 80)
                {
                    nahled = (nahled).Substring(0, 80) + "...";
                }

                viewModels.Add(new ProposalViewModel
                {
                    Id = i.Id,
                    CreationDate = i.CreationDate,
                    Text = nahled,
                    ReleaseDate = i.ReleaseDate
                });
            }
            return viewModels;
        }

a funguje to přesně podle mých představ

Nahoru Odpovědět
2.2.2017 12:57
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
vajkuba1234
Člen
Avatar
Odpovídá na Michal Štěpánek
vajkuba1234:2.2.2017 13:22

Asi bych to neoznacil za moc stastne reseni davat nejakou praci se stringem do metody, ktera se stara o mapping. Proc si to nevytahnes v indexu podle tvych predstav a znovu ve view kompletni objekt?

Nahoru Odpovědět
2.2.2017 13:22
No hope, no future, JUST WAR!
Avatar
Odpovídá na vajkuba1234
Michal Štěpánek:2.2.2017 15:51

Proc si to nevytahnes v indexu podle tvych predstav a znovu ve view kompletni objekt?

Můžeš mi to trošku objasnit?

Nahoru Odpovědět
2.2.2017 15:51
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
vajkuba1234
Člen
Avatar
Odpovídá na Michal Štěpánek
vajkuba1234:2.2.2017 15:56

V Indexu si vytahnes pouze Id a 80 znaku z Textu, namapujes na viemodel a posles do view. V Detailu si pak namapujes vsechny property, ktere ve view potrebujes a posles do view.

K tomu slouzi prave ten viewmodel. Predstav si, ze mas model, ktery obsahuje 20 properties, ale v Indexu ti staci pouze 5 properties, prece to tam cele nenarves, ne? Proto si vytvoris treba IndexViewModel, ktery obsahuje prave tech 5 potrebnych properties, namapujes model do IndexViewmodel a ten posles do view.

V Detailu, kdyz budes potrebovat treba 15 properties, provedes uplne stejny scenar. Proste 1 view == 1 viewmodel.

Nahoru Odpovědět
2.2.2017 15:56
No hope, no future, JUST WAR!
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 27 zpráv z 27.