Laden...

[gelöst] MVC3: Fragen zur Nutzung mit Entity Framework4

Erstellt von Stipo vor 12 Jahren Letzter Beitrag vor 12 Jahren 4.672 Views
Stipo Themenstarter:in
699 Beiträge seit 2007
vor 12 Jahren
[gelöst] MVC3: Fragen zur Nutzung mit Entity Framework4

Hallo zusammen,

im moment bin ich die einzelnen Frameworks am durchprobieren, das ich entscheiden kann, welchen Weg ich gehen soll.

Im ASP.NET MVC3 Modeliert man ja die Models, das man damit die Daten an die jeweiligen Views binden kann. In den Models wird die Validierungslogik mit untergebracht, was dann zu sehr kompakten Code führt.

Beim Entity Framework4 kann man mit POCO ( Model-First ) das Mapping zur Datenbank durchführen.

Nun meine Frage:
Kann ich für das Mapping der Datenbank dann die selben Models aus dem ASP.NET MVC3 verwenden, oder stört sich EF4 dann an den Annotations in den Models, welche man ja zum Validieren nutzt? Das würde dann ja einiges an Logik sparen, das man nur 1x die Models pflegen muss, und diese dann 1:1 in die Datenbank bekommt.

Sollte man da eventuell ein Repository noch dazwischen schalten?

Im prinzip hab ich die einzelnen Frameworks verstanden. Von Details bin ich im moment aber noch weit entfernt. Mir geht es darum, heraus zu finden, welchen weg ich weiter gehen muss. Also wo ich noch lesen muss.

Wenn also jemand noch ein entscheidende Tips hat, bitte immer her damit.

Grüße Stephan

16.828 Beiträge seit 2008
vor 12 Jahren

Hallo,

also ich rate von der Code First Variante ab!
Habe ziemlich schlechte Erfahrung bei der Wartung von Code und Datenbank mit dieser Variante gemacht und empfehle jedem nicht Code First zu nutzen, ausser er hat wirklich viel Zeit und Nerven, die er opfern möchte!

Ich empfehle den Weg über den Designer seine Entities zu erstellen, und anschließend über den POCO Entity Generator seine Entities zu erstellen.

Anschließend erstellst Du Dir Metadata-Klassen, in denen die Data Annoatiations gelegt werden. Diese werden der Entity-Klasse mit MetadataType injeziert. Über das Implementieren von IValidateable kannst Du zusätzlich logische Validierungen durchführen ( wirft die Fehler direkt in den ModelState ).

    public class EntityMetadata
    {
        // Hier die Data Annotations implementieren
       [Required]
       public string Name {get;set;}
    }

    [MetadataType(typeof(EntityMetadata))]
    public partial class Entity: IValidatableObject
    {
        public IEnumerable<ValidationResult> Validate()
        {
            // hier logische Validierungen, zB um Relationen oder einfache Abhängigkeiten zu prüfen

           if ( this.StartDate > this.EndDate )
           {
                return yield new ValidateResult("Das StartDate kann nicht groesser sein");
           }
        }


        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            // Zugriff auf die Validate-Funktion, um eine manuelle Validierung durchführen zu können.
            return Validate();
        }
    }

Für den Zugriff unbedingt Repositories nutzen - unbedingt!
Erstelle für jedes Entity ein eigenes Repository, die wiederum von einem Repository erben, das Standardfunktionen (Add, Delete, Save, Get, GetMany..) bereitstellt. Spezifische Abfragen für ein bestimmtes Entity gehören dann in das EntityRepository.

Stipo Themenstarter:in
699 Beiträge seit 2007
vor 12 Jahren

Hallo Abt,

danke erstmal für den Ratschlag. Ein paar Fragen hätte ich trotzdem noch dazu.

also ich rate von der Code First Variante ab!
Habe ziemlich schlechte Erfahrung bei der Wartung von Code und Datenbank mit dieser Variante gemacht und empfehle jedem nicht Code First zu nutzen, ausser er hat wirklich viel Zeit und Nerven, die er opfern möchte!

Was genau sind da deine Erfahrungen? Muss man da umständlich dann die Datenbanken nachziehen? Denn so wie ich das verstanden habe aus dem WebCast, muss man da ja die Datenbank nicht explizit selbst designen, sondern erstellt nur das Mapping und die Objecte und kann das dann nutzen. ( Soll nun aber erstmal nebensächlich sein, ob da mein Wissen korrekt ist, denn dein ansatz möchte ich auch erstmal erforschen )

Ich empfehle den Weg über den Designer seine Entities zu erstellen, und anschließend über den POCO Entity Generator seine Entities zu erstellen.

Anschließend erstellst Du Dir Metadata-Klassen, in denen die Data Annoatiations gelegt werden. Diese werden der Entity-Klasse mit MetadataType injeziert. Über das Implementieren von IValidateable kannst Du zusätzlich logische Validierungen durchführen ( wirft die Fehler direkt in den ModelState ).

Gehe ich da recht in der annahme, das ich dann für das MVC trotzdem noch ein Model erstellen muss, das sich rein um die Anzeige kümmert? Wenn ich das mit dem Repository richtig verstanden habe, müsste ich darin dann ja die umsetzung machen, von dem Model, was man vom Controller bekommt, in die Entität für die Datenbank und umgekehrt.

Im moment ist das noch ein bisschen wirr in meinem Kopf. Versuche da nun ein bisschen Ordnung rein zu bekommen 😉
Die meisten Beispiele die man im Internet findet, behandeln ja nur kleine teilausschnitte des ganzen, aber nie im gesamten als Projekt.

Ich werde mich nun mal ein bisschen mit deinem Vorschlag befassen.

Grüße Stephan

16.828 Beiträge seit 2008
vor 12 Jahren

Was genau sind da deine Erfahrungen? Muss man da umständlich dann die Datenbanken nachziehen? Denn so wie ich das verstanden habe aus dem WebCast, muss man da ja die Datenbank nicht explizit selbst designen, sondern erstellt nur das Mapping und die Objecte und kann das dann nutzen. ( Soll nun aber erstmal nebensächlich sein, ob da mein Wissen korrekt ist, denn dein ansatz möchte ich auch erstmal erforschen )

* Ich arbeite gerne mit vorkompilierten Quieres - mit Code First nicht möglich.
* Meine Datenbank wird oft erweitert (neue Tabelle, neue Spalten) und dies im Designer des SQL Management Studios zu pflegen, und die Entitäten automatisch über den EDMX Designer aktualisieren zu lassen ist deutlich angenehmer und einfacher
* Relationen sind in im Designer einfacher und klarer zu definieren ( womit ich die größten Probleme unter CF hatte, die teilweise auch als Bugs im CTP5 definiert wurden ( keine Ahnung ob die mit dem Release weg sind, bin froh, dass ich kein CF mehr habe! )
* Die Data Annoations werden übersichtlicher gekapselt

Gehe ich da recht in der annahme, das ich dann für das MVC trotzdem noch ein Model erstellen muss, das sich rein um die Anzeige kümmert? Wenn ich das mit dem Repository richtig verstanden habe, müsste ich darin dann ja die umsetzung machen, von dem Model, was man vom Controller bekommt, in die Entität für die Datenbank und umgekehrt.

Nein. Du hast keine ViewModelle.
Du übergibst Dein Datenbankobjekt direkt View(Page) und stellst die Werte dort im Editor zur Verfügung.
Am Save-Controller erhälst Du anschließend direkt eine gefüllte Entity (model).
Anschließend holst Du Dir das Datenbankobjekt (dbItem), das aktualisiert werden soll.
Anschließend führst Du UpdateModel(dbItem) aus und die Funktion übernimmt automatisch die Werte von model in dbItem. Mit einem zusätzlichen Interface UpdateModel<IEntityUpdateInterface>(dbItem) kannst Du zusätzlich sehr einfach bestimmen, welche Properties Du aktualisiert haben möchtest.


[HttpPost]
public ActionResult Save(int id, Entity model)
{

    var dbItem = this.MyEntityRepository.Get(ent => ent.ID.Equals(id) );

   if ( Model.IsValid ) 
   {
       UpdateModel<IMySpecificEntityUpdateINterface>(dbItem);
       this.MyEntityRepository.Save();
       return View("Saved");
   }

   return View("InvalidModel");
}
}
Stipo Themenstarter:in
699 Beiträge seit 2007
vor 12 Jahren

Danke nochmal für die Infos.
Ich muss das nun alles mal evaluieren 😃 Ist im moment ein bisschen viel auf einmal 😉 Aber das backe ich schon zu meinem Kuchen zusammen 😃

Grüße Stephan

PS: Wo aus BW kommst Du eigentlich her 😉

16.828 Beiträge seit 2008
vor 12 Jahren

Ist halt alles eine zentrale Sache. Muss man vor Entwicklungsbeginn evaluieren und alles schön modular halten, damit man eben doch wechseln kann.

Ich komm aus unsrer schönen, protestreichen Landeshauptstadt 😉

Stipo Themenstarter:in
699 Beiträge seit 2007
vor 12 Jahren

So nun komme ich zum ersten Problem 😃

Ich hab mir nun mal im EDMX Designer eine Entität erstellt ( Person ).
Wenn ich nun als Codegenerierungselement den "ADO.NET POCO Entity Generator" nutze, erstellt der mir ja saubere Klassen von meinen Entitäten.


//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated from a template.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;

namespace EFEval.Library
{
    public partial class Person
    {
        #region Primitive Properties
    
        public virtual int ID
        {
            get;
            set;
        }
    
        public virtual string Name
        {
            get;
            set;
        }
    
        public virtual string Anrede
        {
            get;
            set;
        }
    
        public virtual string Alter
        {
            get;
            set;
        }
    
        public virtual string Beruf
        {
            get;
            set;
        }

        #endregion
    }
}

Da die Klasse aber "Auto-Generated" ist, überschreibt der mir ja jede Änderung, die ich darin machen würde.
Also komme ich im moment nicht ganz dahinter, was du oben mit deinem Code Beispiel meinst.

Muss ich dazu das Codegenerierungs-Template anpassen? Und darin alles raus werfen, was den Code in der Primitive Properties Region schreibt.
Den Code wie in deinem Beispiel könnte ich ja in eine eigene Datei packen ( partial ).

Hast Du das so gemeint? Oder bin ich da auf dem falschen Dampfer unterwegs.

Grüße Stephan

16.828 Beiträge seit 2008
vor 12 Jahren

Nein, Du fässt die generierten Dateien nicht an. Und ja Du erweiterst die Klasse via partial.

Du machst eine neue Datei, eine PersonMetadata.cs und eine PersonExtensions.cs
In die Metadata kommt das Beispiel des Metdata rein, und die PersonExtension erweiterter die Klasse Person 😃

Stipo Themenstarter:in
699 Beiträge seit 2007
vor 12 Jahren

Okay, dann hab ich das soweit verstanden 😃

Dann kann es ja fast schon losgehen mit dem Projekt. Hab somit die wichtigsten Details erörtert 😉

Details werden dann später sicher noch auftauchen, die ich dann erfragen muss.

Grüße Stephan

Stipo Themenstarter:in
699 Beiträge seit 2007
vor 12 Jahren

Hallo Abt,

ich muss mal noch etwas nachfragen 😃

Für den Zugriff unbedingt Repositories nutzen - unbedingt!
Erstelle für jedes Entity ein eigenes Repository, die wiederum von einem Repository erben, das Standardfunktionen (Add, Delete, Save, Get, GetMany..) bereitstellt. Spezifische Abfragen für ein bestimmtes Entity gehören dann in das EntityRepository.

Hättest Du da eventuell ein gutes Beispiel im Internet auf lager, das Du empfehlen kannst? Da ich noch nicht so richtig Fit im EF bin, suche ich gerade noch den richtigen ansatz, wie ich das Repository generisch umsetzen kann.

Ein kleiner schups reicht aus 😃

Grüße Stephan

1.002 Beiträge seit 2007
vor 12 Jahren

Hallo Stipo,

hier der Ansatz, den ich mit meinen Repositories verfolgt habe. Er ist nicht zu 100% generisch, d.h. im jeweiligen Repository muss die Schnittstelle des Interfaces implementiert und dabei die entsprechende Entity Collection verwendet werden.

Ansonsten hilft dir vielleicht Advantage of creating a generic repository vs. specific repository for each object? weiter.

m0rius

Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg

16.828 Beiträge seit 2008
vor 12 Jahren

Guten Morgen,
Es ist ein allgemeiner Pattern, ich musste leider meine Entity Bezeichnungen jedoch durch Entity1, Entity2, Entity3... umbenennen. Der Pflicht wegen. Die Funktionsweise sollte dennoch klar sein 😉

Die Basisklasse (wie die Interfaces und die konsumierenden Reps aussehen, sollte klar sein):


// Ctor
protected RepositoryBase( EntityDbContext dbContext )
{
    m_dataContext = dbContext;

    m_dbset = DataContext.CreateObjectSet<T>( );
}

// Common
protected EntityDbContext DataContext
{
    get { return m_dataContext; }
}

protected IObjectSet<T> CurrentEntitySet
{
    get { return m_dbset; }
}

public virtual void Add( T entity )
{
    m_dbset.AddObject( entity );
}

public virtual void Delete( T entity )
{
    m_dbset.DeleteObject( entity );
}

public void Delete( Expression<Func<T, Boolean>> where )
{
    IEnumerable<T> objects = m_dbset.Where( where );
    foreach ( T obj in objects )
        m_dbset.DeleteObject( obj );
}

public virtual IEnumerable<T> GetAll( )
{
    return m_dbset;
}

public virtual IEnumerable<T> GetMany( Expression<Func<T, bool>> where )
{
    return m_dbset.Where( where );
}

public T Get( Expression<Func<T, Boolean>> where )
{
    return m_dbset.SingleOrDefault( where );
}

public void Save( )
{
    m_dataContext.SaveChanges( );
} 


Ich kann also im konsumierenden Repository die Basis-Funktionen von RepositoryBase nutzen; jedoch auch einfach ersetzten, wenn ich zB in der Add-Funktion noch bestimmte Werte setzen/ändern/aktualisieren will.
Ebenso können im EntityRepository spezifische Entity-Abfragen hinterlegt werden.

Die Repositories sind so aufgebaut, dass nur eine einzige Connection EntityDbContext verwendet wird, die ich einmalig vor dem Erstellen allen Repositories aufbaue und dann via Konstruktor übergebe.
Zwar nutze ich im Entity3 Repository ein IDisposable, aber das tut nichts - es ist leer.
Es ist einfach nur wegen dem Code-Design, sodass ich hier ein übersichtliches using nutzen kann.

Stipo Themenstarter:in
699 Beiträge seit 2007
vor 12 Jahren

Hallo m0rius, Hallo Abt,

ich hab mir beide Beispiele angesehen, und denke mal den ansatz gefunden.
Ich stürze mich dann mal ins vergnügen und beginne mein Projekt 🙂
Learning by doing. Da findet man dann am schnellsten wissenslücken und probleme, die man noch hat. Ich sag meinen Lehrlingen auch immer, aus Fehler muss man lernen, das man die das nächste mal nicht mehr macht 😉

Bei allfälligen Fragen, weiß ich ja, wo ich gute kompetente Hilfe bekomme 🙂

Danke nochmal, für die tips und hilfe.

Grüße Stephan