Ich arbeite zur Zeit mit ASP .NET Core 1.0 mit Entity Framework Core. Ich habe einige komplexe Berechnungen mit Daten aus der Datenbank und ich bin nicht sicher, wie man eine richtige Architektur ohne Aufbau eines anämischen Domänenmodell (http://www.martinfowler.com/bliki/AnemicDomainModel.html)Domain Model und zugehörige Daten (Anemic Domain Model)
(vereinfacht) Beispiel für die Verwendung Dependency Injection bauen:
ich habe folgende Einheiten:
public class Project {
public int Id {get;set;}
public string Name {get;set;}
}
public class TimeEntry
{
public int Id {get;set;}
public DateTime Date {get;set;}
public int DurationMinutes {get;set;}
public int ProjectId {get;set;}
public Project Project {get;set;}
}
public class Employee {
public int Id {get;set;}
public string Name {get;set;}
public List<TimeEntry> TimeEntries {get;set;}
}
ich möchte einige komplexe Berechnungen tun, um eine monatliche Timesheet zu berechnen. Da ich nicht auf die Datenbank innerhalb der Employee-Entität zugreifen kann, berechne ich das TimeSheet in einer EmployeeService
.
public class EmployeeService {
private DbContext _db;
public EmployeeService(DbContext db) {
_db = db;
}
public List<CalculatedMonth> GetMonthlyTimeSheet(int employeeId) {
var employee = _db.Employee.Include(x=>x.TimeEntry).ThenInclude(x=>x.Project).Single();
var result = new List<CalculatedMonth>();
//complex calculation using TimeEntries etc here
return result;
}
}
Wenn ich die Timesheet erhalten will, muss ich die EmployeeService injizieren und GetMonthlyTimeSheet
nennen.
Also - ich am Ende mit vielen GetThis() und GetThat() Methoden in meinem Service, obwohl diese Methoden würde perfekt in die Employee
Klasse selbst passen.
Was ich will, erreichen, ist so etwas wie:
public class Employee {
public int Id {get;set;}
public string Name {get;set;}
public List<TimeEntry> TimeEntries {get;set;}
public List<CalculatedMonth> GetMonthlyTimeSheet() {
var result = new List<CalculatedMonth>();
//complex calculation using TimeEntries etc here
return result;
}
}
public IActionResult GetTimeSheets(int employeeId) {
var employee = _employeeRepository.Get(employeeId);
return employee.GetTimeSheets();
}
... aber, dass ich sicherstellen müssen, dass die Liste der TimeEntries aus der Datenbank gefüllt wird (EF-Core nicht verzögertes Laden nicht unterstützt) . Ich möchte nicht .Include (x => y) alles bei jeder Anfrage, weil ich manchmal nur den Namen des Mitarbeiters ohne die Zeiteinträge benötigt und es würde die Leistung der Anwendung beeinträchtigen.
Kann mir jemand in eine Richtung zeigen, wie man das richtig baut?
Edit: Eine Möglichkeit (aus den Kommentaren der ersten Antwort) wäre:
public class Employee {
public int Id {get;set;}
public string Name {get;set;}
public List<TimeEntry> TimeEntries {get;set;}
public List<CalculatedMonth> GetMonthlyTimeSheet() {
if (TimeEntries == null)
throw new PleaseIncludePropertyException(nameof(TimeEntries));
var result = new List<CalculatedMonth>();
//complex calculation using TimeEntries etc here
return result;
}
}
public class EmployeeService {
private DbContext _db;
public EmployeeService(DbContext db) {
_db = db;
}
public Employee GetEmployeeWithoutData(int employeeId) {
return _db.Employee.Single();
}
public Employee GetEmployeeWithData(int employeeId) {
return _db.Employee.Include(x=>x.TimeEntry).ThenInclude(x=>x.Project).Single();
}
}
public IActionResult GetTimeSheets(int employeeId) {
var employee = _employeeService.GetEmployeeWithData(employeeId);
return employee.GetTimeSheets();
}
Der erste Schritt, um in das Anemic-Domänenmodell zu gelangen, besteht darin, Ihre Setter 'privat' zu machen und korrekte Konstruktoren der Objekte mit Parametervalidierung zu erstellen. Auch wenn Sie mit EF arbeiten, benötigen Sie mindestens einen 'geschützten' Konstruktor, wenn Ihre 'öffentlichen' Konstruktoren nicht parameterlos sind, wie ich es vorschlage. –
Ich denke, es ist Arbeit, wenn man bedenkt, wie Sie Ihr Modell testen können. Den Code testbar zu machen, ist oft, IMHO, eine ausgezeichnete Möglichkeit, Design-Probleme und ihre Lösungen herauszufordern. Sind Sie zum Beispiel froh, dass Sie Ihren 'EmployeeService' mit dem obigen Design testen (Einheit oder Integration) können? –
@ Jetro223 wie Sie es vorgestellt haben, ist Ihr Modell ** anämisch, ob Sie es wollen oder nicht. – guillaume31