myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
» Regeln
» Wie poste ich richtig?
» Forum-FAQ

Mitglieder
» Liste / Suche
» Wer ist wo online?

Ressourcen
» openbook: Visual C#
» openbook: OO
» Microsoft Docs

Team
» Kontakt
» Übersicht
» Wir über uns

» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Entwicklung » Rund um die Programmierung » Entity Framework-Klassen und Darstellung in der View
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

Entity Framework-Klassen und Darstellung in der View

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
Rioma Rioma ist männlich
myCSharp.de-Mitglied

Dabei seit: 31.10.2013
Beiträge: 228
Entwicklungsumgebung: Visual Studio 2015 Pro


Rioma ist offline

Entity Framework-Klassen und Darstellung in der View

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo zusammen,

wie handhabt ihr die Entitäten bezüglich anzuzeigender Daten? Ich lese sehr oft, dass Entitäten nichts im ViewModel verloren haben, leider machen das Microsoft beispiele häufig so. Ich nehme an, dass ihr die Entitäten dann nochmal auf Models für die View mapped
(von mir aus: PersonEntität wird zu Person oder so ähnlich).

Falls ja:


1. Warum dieser Vorgang? nur weil ein paar Spalten aus der Datenbank nicht in der View gebraucht werden, oder hat das noch andere Gründe? (man könnte per Fluent Api ja auch einige Spalten außen vor lassen)

2. Wo findet dieser Vorgang statt? --> BusinessLayer?

3. Benutzt ihr Frameworks wie Automapper dafür?

4. Hat jemand vielleicht sogar ein Beispiel, wo man sich so etwas angucken und nachvollziehen kann?[/list=1]Danke euch :)

Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Rioma am 03.06.2015 15:02.

03.06.2015 15:01 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
MorphieX MorphieX ist männlich
myCSharp.de-Mitglied

Dabei seit: 06.02.2012
Beiträge: 184
Entwicklungsumgebung: VS 2015 Community
Herkunft: Rahden


MorphieX ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Darüber denke ich auch sehr oft nach...

So bin ich sonst immer vorgegangen:
Model (POCO-Klassen) erstellt und INotifyPropetyChanged implementiert
Wenn es berechnete Properties (z.B. Menge * Einzelpreis = Gesamtpreis) sind, die nicht zur Datenbank gehören, benutze ich das [NotMapped]-Attribute.
Dieses Model benutze ich dann mit dem EntityFramework als Entität
Bei mir sind die Views meist Fenster, dafür erstelle ich separate ViewModels. Diese ViewModels besitzen dann aber meist ein Objekt mit einer Instanz einer Entität, die ich jetzt ebenfalls an die View binden kann, oft auch eine ObservableCollection einer Entität.

Damit bin ich bis jetzt immer gut zurecht gekommen.
Man liest aber immer wieder, dass das "nicht richtig" oder "schlecht" sei...

Darum überlege ich mir zur Zeit dieses Konstrukt:

Die Entitäten (wieder POCO-Klassen) besitzen wirklich nur die Properties, die sie wirklich abspeichern wollen
Zu jeder Entität gibt es eine abstrakte Basis-ViewModel-Klasse, die alle Properties der Entität 1:1 nachbilden, zusätzlich aber noch INotifyPropertyChanged implementieren
Diese Basisklassen würde ich mir über eine T4-Vorlage automatisch erzeugen lassen...
Dann gibt es zu jeder Entität mindestens ein ViewModel, welches von der Basisklasse erbt, zusätzlich aber noch weitere Properties zur Verfügung stellt (z.B. Menge * Einzelpreis = Gesamtpreis)

Dann gibt es wieder für jedes Fenster ein ViewModel, welches mindestens eine Instanz der Entity-ViewModels besitzt. Also dasselbe wie oben, nur dass nicht direkt auf die Models gebunden wird, sondern noch die VM-Klasse dazwischen liegt.

Wäre das vielleicht ein "richtigerer" weg? ;-)
03.06.2015 15:49 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Coffeebean Coffeebean ist männlich
myCSharp.de-Team

avatar-3295.gif


Dabei seit: 25.08.2011
Beiträge: 2.208
Entwicklungsumgebung: VS 2005-2017, VS Code
Herkunft: Deutschland/Schweiz


Coffeebean ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Im Asp.Net-Bereich nimmt man oft DTOs dafür.

Das sind Objekte, die speziell nur das enthalten, was die View braucht. Dafür benutze ich eine Factory und mappe das Ganze. Vor dem return ein

C#-Code:
....Select(x => _myFactory.Create(x));

und es werden DTOs zurückgegeben.

Da du nicht geschrieben hast, in welchem Umfeld wir uns befinden komme ich jetzt einfach mal mit dem Asp.Net-Fall.

 Asp.Net: Create Data Transfer Objects (DTOs)

Zu 1) Siehe Link
Zu 2) Je nach Umgebung. Baust du eine SPA kannst dus ein wenig anders machen als in einer MVVM-Umgebung. Wie so oft: Kommt darauf an.
Zu 3) Kann man machen, ja.  Github - Automapper
Zu 4) Siehe Link.

Gruss

Coffeebean
03.06.2015 15:58 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Rioma Rioma ist männlich
myCSharp.de-Mitglied

Dabei seit: 31.10.2013
Beiträge: 228
Entwicklungsumgebung: Visual Studio 2015 Pro

Themenstarter Thema begonnen von Rioma

Rioma ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Danke erstmal für eure Antworten.

Umfeld wäre C# + WPF + MVVM + EF6 + MSSQL 2014

Ich denke aber dass sich das Asp.Net Beispiel recht gut übertragen lässt.

Mein vorgehen wäre dann wahrscheinlich wie schon im ersten Post angedeutet:

DAL gibt Entitäten zurück und im BL erzeuge ich mir daraus meine Objekte für die View und reiche diese entsprechend bis ins ViewModel.

Aber wo ist der große vorteil die Objekte von ein paar Properties zu befreien und wie oft kommt es vor, dass eine Entität Daten enthält, die die View nicht braucht?

Mein vorgehen war bisher EF6 CodeFirst und ich habe mir hier überlegt, was ich für Daten brauche. Rausfallen für die View, würde zum Beispiel die entsprechende ID, aber rechtfertigt die ID den Mehraufwand? Kann sich hier vielleicht jemand ein Praxis bezogenes Beispiel eines bestimmten Objektes (z.B. wie oben beschrieben PersonEntität wird zu Person --> was kann wegfallen/kommt hinzu) in diesem Umfeld aus den Fingern "saugen"?
03.06.2015 16:27 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Abt
myCSharp.de-Team

avatar-4119.png


Dabei seit: 20.07.2008
Beiträge: 14.461
Herkunft: BW


Abt ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Zitat von Rioma:
Aber wo ist der große vorteil die Objekte von ein paar Properties zu befreien und wie oft kommt es vor, dass eine Entität Daten enthält, die die View nicht braucht?

In vermutlich 99% aller Fälle.
Es geht ja nicht nur darum, dass eine View weniger Eigenschaften braucht als ein Objekt hat - sondern meist umgekehrt:

In einer Benutzerregistrierung gibt es oft eine Länderauswahl - ergo eine Liste.
Das Datenbank-Objekt hat aber nur eine Eigenschaft; nämlich das Land, das er sich eben ausgesucht hat.

Hinzu kommt, dass Views meist völlig anders zusammengesetzt sind als Entitäten.

AutoMapper gehört aber nicht in den DAL.
 STOP USING AUTOMAPPER IN YOUR DATA ACCESS CODE
 Why mapping DTOs to Entities using AutoMapper and EntityFramework is horrible
03.06.2015 18:19 Beiträge des Benutzers | zu Buddylist hinzufügen
Rioma Rioma ist männlich
myCSharp.de-Mitglied

Dabei seit: 31.10.2013
Beiträge: 228
Entwicklungsumgebung: Visual Studio 2015 Pro

Themenstarter Thema begonnen von Rioma

Rioma ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Alles klar, das ergibt auf jeden Fall Sinn. Automapper hätte ich auch nicht im DAL gehabt, sondern im BL. Ich würde im BL dann die Entitäten aus der Datenbank über den DAL bekommen und hier ein Mapping für die View vornehmen.

Allerdings scheint laut den Links Automapper nicht die beste Variante für EF zu sein. Bzw. erfordert es sehr viel "undurchschaubaren" Code. Darf ich Fragen wie du/ihr dies in einer WPF + MVVM + EF Anwendung realisiert?

Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Rioma am 03.06.2015 20:21.

03.06.2015 20:19 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Abt
myCSharp.de-Team

avatar-4119.png


Dabei seit: 20.07.2008
Beiträge: 14.461
Herkunft: BW


Abt ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Da wir komplett auf IQueryable setzen, mappen wir komplett alles mit eigenen Implementierungen, die eine Mischung Repository- und Adapter Pattern.

C#-Code:
public interface IMapper<T1, T2> {}

public abstract class Mapper<T1, T2> : IMapper<T1, T2>
{
// Gemeinsame Implementierungen, zB Collections hier.
// abstrakte Methode für konkrete Implementierung
}

public interface ICurrencyMapper : IMapper<BackendModels.Currency, EntityModels.Currency> {}

public class CurrencyMapper : Mapper<BackendModels.Currency, EntityModels.Currency>, ICurrencyMapper
{
// konkrete Implementierungen
}

public interface IArticleMapper : IMapper<BackendModels.Article, EntityModels.Article> {}

public class ArticleMapper : Mapper<BackendModels.Article, EntityModels.Article>, IArticleMapper
{
// konkrete Implementierungen
public ArticleMapper (IArticleRepository rep, ICurrencyMapper currencyMapper()
{
}

}
03.06.2015 20:30 Beiträge des Benutzers | zu Buddylist hinzufügen
Zwischen diesen beiden Beiträgen liegt mehr als ein Jahr.
t0ms3n t0ms3n ist männlich
myCSharp.de-Mitglied

Dabei seit: 13.01.2013
Beiträge: 314


t0ms3n ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Der Artikel ist zwar etwas älter, aber dazu folgende Frage. (Kann gerne abgeleitet werden, sofern sinnvoll).

Nehmen wir folgendes Repository...

C#-Code:
    public interface IRepository<TEntity>
    {
        TEntity FindById(int id);
        ....
    }

Möchte ich nun irgendwo nur bestimmte Daten dieser Entität nutzen, kann ich diese entsprechend mappen. Dies ändert aber nichts an der Abfrage die gegen die Datenbank läuft.

Abt sagte, dass sie vollständig auf IQueryable setzen. Folglich sähe das Repository so aus ?:

C#-Code:
    public interface IRepository<TEntity>
    {
        IQueryable<TEntity> FindById(int id);
        ....
    }

Ist es nun der sauberere Weg, dies so zu tun und z.B. im BL entsprechend die gewünschte Projection vorzunehmen?

Oder nutzt ihr, da Tools wie AutoMapper (mittlerweile) ja auch mit IQueryable entsprechend umgehen können diese im DAL, sodass ein Repository z.B. so aussieht und kein IQueryable verfügbar gemacht wird:

C#-Code:
    public interface IRepository<TEntity>
    {
        TModel FindById<TModel>(int id);
        ....
    }
17.06.2016 10:31 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Coffeebean Coffeebean ist männlich
myCSharp.de-Team

avatar-3295.gif


Dabei seit: 25.08.2011
Beiträge: 2.208
Entwicklungsumgebung: VS 2005-2017, VS Code
Herkunft: Deutschland/Schweiz


Coffeebean ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo t0ms3n,

wenn du mit IQueryable arbeitest würde ich bei ASP.NET mit OData, den Query-Options und eben IQueryable auch bei einer Single-Entity arbeiten. Somit kannst du dir erstmal mit mit einer Where() klausel mit der ID die eine Entity als Queryable holen und dann die SingleResult.Create(); Methode benutzen. OData Queryoptions werden dann darauf angewandt und wenn du dir das Query ggn die Datenbank anschaust siehst du, dass nur deine Felder abgerufen werden.

C#-Code:
[HttpGet]
        [EnableQuery]
        [ODataRoute("Houses({id})")]
        public IHttpActionResult GetSingleHouse([FromODataUri] int id)
        {
            IQueryable<HouseEntity> house = _houseRepository.GetAll().Where(x => x.Id == id);

            if (!house.Any())
            {
                return NotFound();
            }

            return Ok(SingleResult.Create(house));
}

Aufruf zum Beispiel: http://localhost:3153/odata/Houses(1)?$select=Street, City

 SingleResult.Create<T> Method

Gruss

Coffeebean
17.06.2016 10:40 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
t0ms3n t0ms3n ist männlich
myCSharp.de-Mitglied

Dabei seit: 13.01.2013
Beiträge: 314


t0ms3n ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hmmm, die Verwendung von OData ist an der Stelle doch aber nur bedingt relevant. Die eigentliche Frage ist ja, wann und wo ich eine Entität des DALs in eine entsprechend DTO/ViewModel wandle?

Der OData Fall spräche allerdings für das zweite Beispiel, also das mein Repository immer IQueryable liefert und (um bei ASP.NET zu bleiben) der Controller die Projektion durchführt, welche selbst ja auch wieder ein IQueryable ist.
17.06.2016 11:19 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum Der Startbeitrag ist älter als 5 Jahre.
Der letzte Beitrag ist älter als 4 Jahre.
Antwort erstellen


© Copyright 2003-2021 myCSharp.de-Team | Impressum | Datenschutz | Alle Rechte vorbehalten. | Dieses Portal verwendet zum korrekten Betrieb Cookies. 21.01.2021 05:41