Ich bin ziemlich neu in DDD Welt und nachdem ich einige Bücher darüber gelesen (Evans DDD unter ihnen) Ich konnte nicht die Antwort auf meine Frage im Internet finden: Was ist der richtige Weg Erstellen von untergeordneten Entitäten mit DDD? Sie sehen, viele Informationen im Internet funktionieren auf einer einfachen Ebene. Aber Teufel in den Details und sie sind immer in Dutzenden von DDD-Proben aus Gründen der Einfachheit weggelassen.Proper Art der Erstellung von Kind-Entitäten mit DDD
Ich komme aus my own answer auf Similair Frage hier auf Stackoverflow. Ich bin nicht ganz mit meiner eigenen Vision zu diesem Problem zufrieden, also dachte ich, ich müsste das genauer ausführen.
Zum Beispiel muss ich ein einfaches Modell erstellen, die Autos Namen darstellen: Unternehmen, Modell und Modifikation (zum Beispiel, Nissan Teana 2012 - das wird "Nissan" Unternehmen, "Teana" Modell und "2012" Modifikation).
Die Skizze des Modells Ich möchte so aussieht erstellen:
CarsCompany
{
Name
(child entities) Models
}
CarsModel
{
(parent entity) Company
Name
(child entities) Modifications
}
CarsModification
{
(parent entity) Model
Name
}
So, jetzt muss ich Code erstellen. Ich verwende C# als Sprache und NHibernate als ORM. Dies ist wichtig und wird normalerweise nicht in umfangreichen DDD-Beispielen im Internet angezeigt.
Der erste Ansatz.
Ich beginne mit einfachen Ansatz mit typischen Objekterstellung über Factory-Methoden.
public class CarsCompany
{
public virtual string Name { get; protected set; }
public virtual IEnumerable<CarsModel> Models { get { return new ImmutableSet<CarsModel> (this._models); } }
private readonly ISet<CarsModel> _models = new HashedSet<CarsModel>();
protected CarsCompany()
{
}
public static CarsCompany Create (string name)
{
if (string.IsNullOrEmpty (name))
throw new ArgumentException ("Invalid name specified.");
return new CarsCompany
{
Name = name
};
}
public void AddModel (CarsModel model)
{
if (model == null)
throw new ArgumentException ("Model is not specified.");
this._models.Add (model);
}
}
public class CarsModel
{
public virtual CarsCompany Company { get; protected set; }
public virtual string Name { get; protected set; }
public virtual IEnumerable<CarsModification> Modifications { get { return new ImmutableSet<CarsModification> (this._modifications); } }
private readonly ISet<CarsModification> _modifications = new HashedSet<CarsModification>();
protected CarsModel()
{
}
public static CarsModel Create (CarsCompany company, string name)
{
if (company == null)
throw new ArgumentException ("Company is not specified.");
if (string.IsNullOrEmpty (name))
throw new ArgumentException ("Invalid name specified.");
return new CarsModel
{
Company = company,
Name = name
};
}
public void AddModification (CarsModification modification)
{
if (modification == null)
throw new ArgumentException ("Modification is not specified.");
this._modifications.Add (modification);
}
}
public class CarsModification
{
public virtual CarsModel Model { get; protected set; }
public virtual string Name { get; protected set; }
protected CarsModification()
{
}
public static CarsModification Create (CarsModel model, string name)
{
if (model == null)
throw new ArgumentException ("Model is not specified.");
if (string.IsNullOrEmpty (name))
throw new ArgumentException ("Invalid name specified.");
return new CarsModification
{
Model = model,
Name = name
};
}
}
Das Schlimme an diesem Ansatz ist, dass die Schaffung des Modells nicht an die übergeordneten Modell Sammlung nicht hinzugefügt:
using (var tx = session.BeginTransaction())
{
var company = CarsCompany.Create ("Nissan");
var model = CarsModel.Create (company, "Tiana");
company.AddModel (model);
// (model.Company == company) is true
// but (company.Models.Contains (model)) is false
var modification = CarsModification.Create (model, "2012");
model.AddModification (modification);
// (modification.Model == model) is true
// but (model.Modifications.Contains (modification)) is false
session.Persist (company);
tx.Commit();
}
Nachdem die Transaktion verpflichtet ist und die Sitzung gespült wird, wird die ORM schreibe alles korrekt in die Datenbank und wenn wir das nächste Mal diese Firma laden, wird die Model Collection unser Modell korrekt halten. Das Gleiche gilt für die Modifikation. Bei diesem Ansatz bleibt unsere übergeordnete Entität in einem inkonsistenten Zustand, bis sie von der Datenbank erneut geladen wird. No Go.
Der zweite Ansatz.
Dieses Mal werden wir die sprachspezifische Option verwenden, um das Problem der Einstellung geschützter Eigenschaften anderer Klassen zu lösen - nämlich den Modifier "protected internal" für Setter und Konstruktor.
Dieses Mal wird bei jeder Entitätserstellung sowohl die übergeordnete als auch die untergeordnete Entität im konsistenten Zustand belassen. Aber die Validierung des untergeordneten Entitätsstatus ist in die übergeordnete Entität gelaufen (AddModel
und AddModification
Methoden). Da ich kein DDD-Experte bin, bin ich mir nicht sicher, ob es in Ordnung ist oder nicht. Es könnte in Zukunft weitere Probleme verursachen, wenn untergeordnete Entitätseigenschaften nicht einfach über Eigenschaften festgelegt werden könnten und das Einrichten eines Zustands basierend auf übergebenen Parametern eine komplexere Arbeit erfordern würde, die der Eigenschaft den Parameterwert zuweist. Ich hatte den Eindruck, dass wir die Logik der Entität in dieser Entität konzentrieren sollten, wo immer es möglich ist. Für mich verwandelt dieser Ansatz Elternobjekt in eine Art Entity & Factory Hybrid.
Der dritte Ansatz.
Ok, wir werden die Verantwortung für die Pflege der Eltern-Kind-Beziehungen invertieren.
public class CarsCompany
{
public virtual string Name { get; protected set; }
public virtual IEnumerable<CarsModel> Models { get { return new ImmutableSet<CarsModel> (this._models); } }
private readonly ISet<CarsModel> _models = new HashedSet<CarsModel>();
protected CarsCompany()
{
}
public static CarsCompany Create (string name)
{
if (string.IsNullOrEmpty (name))
throw new ArgumentException ("Invalid name specified.");
return new CarsCompany
{
Name = name
};
}
protected internal void AddModel (CarsModel model)
{
this._models.Add (model);
}
}
public class CarsModel
{
public virtual CarsCompany Company { get; protected set; }
public virtual string Name { get; protected set; }
public virtual IEnumerable<CarsModification> Modifications { get { return new ImmutableSet<CarsModification> (this._modifications); } }
private readonly ISet<CarsModification> _modifications = new HashedSet<CarsModification>();
protected CarsModel()
{
}
public static CarsModel Create (CarsCompany company, string name)
{
if (company == null)
throw new ArgumentException ("Company is not specified.");
if (string.IsNullOrEmpty (name))
throw new ArgumentException ("Invalid name specified.");
var model = new CarsModel
{
Company = company,
Name = name
};
model.Company.AddModel (model);
return model;
}
protected internal void AddModification (CarsModification modification)
{
this._modifications.Add (modification);
}
}
public class CarsModification
{
public virtual CarsModel Model { get; protected set; }
public virtual string Name { get; protected set; }
protected CarsModification()
{
}
public static CarsModification Create (CarsModel model, string name)
{
if (model == null)
throw new ArgumentException ("Model is not specified.");
if (string.IsNullOrEmpty (name))
throw new ArgumentException ("Invalid name specified.");
var modification = new CarsModification
{
Model = model,
Name = name
};
modification.Model.AddModification (modification);
return modification;
}
}
...
using (var tx = session.BeginTransaction())
{
var company = CarsCompany.Create ("Nissan");
var model = CarsModel.Create (company, "Tiana");
var modification = CarsModification.Create (model, "2011");
session.Persist (company);
tx.Commit();
}
Dieser Ansatz bekam alle Validierung/creation Logik in Einheiten entsprechen, und ich weiß nicht, ob es gut oder schlecht ist, sondern durch einfache Erstellung des Objekts mit Factory-Methode zu dem wir es implizit Kindern Sammlung übergeordneten Objekts Hinzufügen . Nach dem Transaktions-Commit und dem Session-Flush gibt es 3 Einfügungen in die Datenbank, obwohl ich noch nie einen "add" -Befehl in meinen Code geschrieben habe. Ich weiß nicht, vielleicht sind es nur ich und meine große Erfahrung außerhalb der DDD-Welt, aber es fühlt sich im Moment ein wenig unnatürlich an.
Also, was ist der korrekte Weg zum Hinzufügen von untergeordneten Entitäten mit DDD?
Ich könnte alle Codebeispiele entfernen und diese ganze Frage viel schwieriger zu verstehen machen - aber ich denke nicht, dass es der Community helfen wird. Mir war nicht bewusst, dass SO nicht für komplexe Fragen steht. –
Die ganze Frage (mit oder ohne Code) ist hier unpassend. Wie gesagt, es fragt nach Diskussion. Lies die Links, die ich gepostet habe. Ich kann einen anderen anbieten: [kein Diskussionsforum oder Forum] (http://meta.stackexchange.com/a/128550/172661). Wie ich bereits sagte, ist diese Seite für ** klare, knappe Fragen, die ohne Diskussion beantwortet werden können **. Da es in Ihrer gesamten Frage darum geht, den "richtigen Weg" zu diskutieren und "Meinungen [sp] zu hören" (was auch hier nicht angebracht ist), ist es hier nicht passend. –
Ich stelle ziemlich konkrete Frage und warte auf eine ganz bestimmte Antwort darauf. Mit meinen Beispielen zeige ich nur die Forschungsanstrengungen, die ich in diese Angelegenheit gesteckt habe. Ich brauche keine Diskussion - ich brauche eine klare Antwort, wie man das richtig macht. Nur weil Sie nicht wissen, Antwort auf diese Frage bedeutet nicht, dass es Diskussion Natur hat. Die DDD-Welt benutzt viele Muster und ich möchte mich auf einen verweisen, den ich anwenden sollte, um dieses spezielle Problem zu lösen. –