Laden...

Business und Persistence Methoden wie implementieren? (Aufteilung Business/Service/DAO/NHibernate)

Erstellt von Powerslave vor 12 Jahren Letzter Beitrag vor 12 Jahren 1.357 Views
P
Powerslave Themenstarter:in
554 Beiträge seit 2005
vor 12 Jahren
Business und Persistence Methoden wie implementieren? (Aufteilung Business/Service/DAO/NHibernate)

Moin,

kurze Frage weil ich hier immer darüber stolpere.

Meine Persistenzschicht besteht aus einem GenericDao<T> und konkreten Dao's die davon ableiten.

Nehmen wir mal an, im UI habe ich die Möglichkeit nach Mitarbeitern zu suchen die mit einem bestimmten Buchstaben anfangen.

Was ist hier nun Best Practise? Ich benötige ja sowohl eine Service als auch eine Dao-Methode.

Natürlich könnte z.B. _employeeService.GetEmployeesStartsWith("A") intern nur _employeeDao.GetEmployeesStartsWith("A") aufrufen die wiederrum per NHibernate den Query absetzt.

Aber das ist doch unschön.

Wie löst ihr sowas?

Danke.

Achtung! - Hinter dir ist ein dreiköpfiger Affe!

1.002 Beiträge seit 2007
vor 12 Jahren

Hallo Powerslave,

für mich gehören Methoden wie _employeeService.GetEmployeesStartingWith("A") ausschließlich in den Service-Layer. Wenn du den Methodenaufruf lediglich an den DataAccess-Layer durchreichst, musst du beim Auswechseln der Datenbanktechnologie all diese Methoden neu implementieren, was unnötig ist.
Stattdessen implementiere ich im DataAccess-Layer lediglich grundlegende Methoden, so zum Beispiel _employeeDao.GetAllEmployees() oder _employeeDao.GetEmployee(int employeeID), und lasse die Logik im Service-Layer — da, wo sie hingehört.

m0rius

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

P
Powerslave Themenstarter:in
554 Beiträge seit 2005
vor 12 Jahren

Hallo,

das heißt du hättest deinen Datenzugriff direkt im ServiceLayer? Dieser sollte eigentlich nicht wissen, wie die Daten geholt werden.

Achtung! - Hinter dir ist ein dreiköpfiger Affe!

1.002 Beiträge seit 2007
vor 12 Jahren

Hallo Powerslave,

nein, der Datenzugriff liegt lediglich im DataAccess-Layer — dafür existiert dieser ja gekapselt. In meinen Projekten habe ich Repositories und Services, die folgendermaßen strukturiert sind:
*Repositories unterstützen üblicherweise nur die Methoden Retrieve(), RetrieveAll(), Save() und Delete(). *Services hingegen besitzen die genannten 4 Methoden, die die Aufrufe einfach nur an die Repositories durchreichen, sowie weitere Methoden, die Anwendungslogik enthalten, wie zum Beispiel RetrieveRandom() (oder wie in deinem Fall GetEmployeesStartingWith("A")).

Ein EmployeeService könnte dann z.B. so aussehen:

public class EmployeeService : IEmployeeService
{
    private readonly IEmployeeRepository _employeeRepository;

    // Hier injizierst du ein Repository für deine spezifische Datenbanktechnologie
    public EmployeeService(IEmployeeRepository employeeRepository)
    {
        _employeeRepository = employeeRepository;
    }

    // Diese Methode wird lediglich durchgereicht ...
    public IQueryable<Employee> RetrieveAll()
    {
        return _employeeRepository.RetrieveAll();
    }

    // Diese Methode wird lediglich durchgereicht ...
    public Employee Retrieve(int employeeID)
    {
        return _employeeRepository.Retrieve(employeeID);
    }

    // Diese Methode wird lediglich durchgereicht ...
    public void Save(Employee employee)
    {
        return _employeeRepository.Save(employee);
    }

    // Diese Methode wird lediglich durchgereicht ...
    public void Delete(Employee employee)
    {
        return _employeeRepository.Delete(employee);
    }

    // Diese Methode enthält Logik, die unabhängig von der Datenbanktechnologie ist.
    // Sie benötigt lediglich eine funktionierende RetrieveAll()-Methode.
    public IQueryable<Employee> RetrieveAllStartingWith(string value)
    {
        return RetrieveAll()
            .Where(employee => employee.StartsWith(value))
            .AsQueryable();
    }
}

Der Vorteil bei dieser Architektur liegt unter anderem darin, dass die Logik von RetrieveAllStartingWith(string value) unabhängig von der Datenquelle ist. Wechselt du also die Technologie, die du zum Persistieren deiner Daten verwendest , musst du lediglich ein neues Repository mit den 4 genannten Repository-Methoden implementieren. Der EmployeeService funktioniert danach immer noch einwandfrei, da sich an der Logik von RetrieveAllStartingWith(string value) ja nichts geändert hat.

m0rius

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

P
Powerslave Themenstarter:in
554 Beiträge seit 2005
vor 12 Jahren

Danke für dein Beispiel,

vielleicht war das "StartsWith"-Beispiel ein schlechtes, da man wie du es eben gezeigt hast, die Einschränkung auch über den Code implementieren kann.

Sagen wir, ich müsste die Einschränkung über ein Query machen, dann wäre es ja (auch in deinem Fall) wieder nur ein Delegieren zum DataLayer.

Achtung! - Hinter dir ist ein dreiköpfiger Affe!

5.742 Beiträge seit 2007
vor 12 Jahren

Hallo Powerslave,

IQueryable<T> ist dein Freund, wenn du mit dem Entity Framework arbeiten kannst.

Diskussionen dazu, ob es wirklich im Repository sein sollte, gibt's unzählige. Google einfach mal nach "repository iqueryable" und wäge die Argumente ab.

Siehe z.B. How can I write a clean Repository without exposing IQueryable to the rest of my application? sowie Repository Pattern - POCOs or IQueryable?.

771 Beiträge seit 2009
vor 12 Jahren

Hi Powerslave,

ich weiß nicht, ob du mit

Sagen wir, ich müsste die Einschränkung über ein Query machen, dann wäre es ja (auch in deinem Fall) wieder nur ein Delegieren zum DataLayer.

Linq (bzw. IQueryable) falsch verstanden hast.
Der Compiler erzeugt aus der Where-Bedingung intern einfach einen ExpressionTree, welcher dann vom Linq-Provider aufgelöst wird, d.h. die Query findet real wirklich auf der Datenbank statt (d.h. es wird ein SQL-Command mit WHERE erzeugt).

Dabei gehe ich davon aus, daß du NHibernate Linq benutzt (bzw. benutzen wirst).

P
Powerslave Themenstarter:in
554 Beiträge seit 2005
vor 12 Jahren

Ja, ich möchte gerne Linq mit NHibernate verwenden.

Kann gut sein, dass ich es noch nicht ganz verstanden habe.

Heißt das, das die Linq-Queries nicht ins Dao gehören, sondern eher in ein Repository bzw. direkt in den ServiceLayer (wenn ich IQueryable verwende)?

Achtung! - Hinter dir ist ein dreiköpfiger Affe!

5.742 Beiträge seit 2007
vor 12 Jahren

Heißt das, das die Linq-Queries nicht ins Dao gehören, sondern eher in ein Repository bzw. direkt in den ServiceLayer (wenn ich IQueryable verwende)?

Genau - insbesondere für etwas komplexere Fälle (also nicht gerade GetAll und GetById - die würde ich weiterhin direkt in den Datenzugriff packen).

Manchmal bietet sich auch die Verwendung des Specification Patterns an - siehe Entity Framework 4 POCO, Repository and Specification Pattern