Hallo Community,
es gibt einen zu nutzenden RestService, welcher mir eine Objecthierarchie mit bis zu 100 Objekten ala
List<Container>=>
Container =>
List<ContainerItem> =>
ContainerItem =>
List<Item> =>
Item
wiedergibt, von denen Ich u.U. sogar die einzelne Items, auch bestimmte Items brauche.
Daher überlege ich mir gerade, wie ich die Datenaufarbeitung am besten realisieren könnte.
Folgende Überlegung:
public class CLAPFactory : IFactory
{
public readonly Container<IAnalyticalActivityP> _activityContainer;
private readonly Container<IAnalyticalElementaryTaskRecord> _aetrContainer;
public CLAPFactory()
{
_activityContainer = new Container<IPersistableData>();
_aetrContainer = new Container<IPersistableData>();
}
public void Persist<TPersistableData>(IList<TPersistableData> collection) where TPersistableData : IPersistableData
{
foreach (var data in collection)
{
_activityContainer.Add(data.Key, (IAnalyticalActivityP)data);
}
}
public void Persist<TPersistableData>(TPersistableData data) where TPersistableData : IPersistableData
{
_activityContainer.Add(data.Key, (IAnalyticalActivityP)data);
}
public TPersistableData LoadableData<TPersistableData>(string key) where TPersistableData : IPersistableData
{
if (typeof(TPersistableData) == typeof(IAnalyticalActivityP))
return (TPersistableData)_activityContainer[key];
if (typeof(TPersistableData) == typeof(IAnalyticalElementaryTaskRecord))
return (TPersistableData)_activityContainer[key];
return default(TPersistableData)
}
}
public interface IFactory
{
void Persist<TPersistableData>(IList<TPersistableData> collection) where TPersistableData : IPersistableData;
void Persist<TPersistableData>(TPersistableData data) where TPersistableData : IPersistableData;
TPersistableData LoadableData<TPersistableData>(string key) where TPersistableData : IPersistableData;
}
public class Container<TPersistableData> : Dictionary<string, TPersistableData> where TPersistableData : IPersistableData
{
public Container()
{
}
public Container(int capacity) : base(capacity)
{
}
public Container(IEqualityComparer<string> comparer) : base(comparer)
{
}
public Container(int capacity, IEqualityComparer<string> comparer) : base(capacity, comparer)
{
}
public Container(IDictionary<string, TPersistableData> dictionary) : base(dictionary)
{
}
public Container(IDictionary<string, TPersistableData> dictionary, IEqualityComparer<string> comparer) : base(dictionary, comparer)
{
}
protected Container(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
}
Wie kann ich verhindern, für jedes TPersistableData-INterface eine eigene Interfaceabfrage zu machen?
(vgl. If(typeof)[...])
Ist dies überhaupt der richtige Ansatz?
Schau dir mal das Entwurfsmuster Visitor an.
es gibt einen zu nutzenden RestService, welcher mir eine Objecthierarchie mit bis zu 100
Ist dies überhaupt der richtige Ansatz?
Prinzipiell ist es eine Bad Practise große, komplexe Objekte mit REST anzunehmen, oder zurück zu geben.
Daher sind Navigation Properties auch nicht Teil der Rückgaben von OData oder anderen Hypermedia-Protokollen wie GraphQL oder Siren.
Das wiederum lässt den Schluss zu, dass Du überhaupt keinen REST sondern einfach einen simplen Json-Service schreibst; denn das schlanke Navigieren über Objekte durch Url-Segmente fällt bei Dir ja flach.
Ich hab sehr viel mit APIs und API Design zutun und noch keinen Grund gefunden, wirklich solche großen Objekte über eine API zurück geben zu müssen.
Was genau ist der Grund, dass es hier der Fall ist?
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Das wiederum lässt den Schluss zu, dass Du überhaupt keinen REST sondern einfach einen simplen Json-Service schreibst; denn das schlanke Navigieren über Objekte durch Url-Segmente fällt bei Dir ja flach.
[...]
Was genau ist der Grund, dass es hier der Fall ist?
Hallo Abt,
Ich muss einen Service aufrufen, welcher basierend auf einer ID eine Struktur als JSON zurückgibt, die oben definiert ist (Exemplarisch):
Eine Liste aus Containern
Jeder **Container **hat eine Liste aus SubContainern.
Jeder **SubContainer **hat eine Liste aus SubContainerEigenschaften
Jede **ContainerEigenschaft **kann, muss aber nicht, eine Liste aus **SubEigenschaften **enthalten
Es können 1-n Container vorkommen
Es können 1-n SubContainer vorkommen
Es können 1-n SubContainerEigenschaften vorkommen
Es können 0-n SubEigenschaten vorkommen.
Stell es dir am besten wie eine Fertigungsprozesskette vor:
Auto ist der Container.
Türenmontieren ist ein SubContainer
Fenster-vorne ist eine SubContainerEigenschaft
Fensterfarbe ist eine SubEigenschaft
[...]
Fenster-hinten ist eine SubContainerEigenschaft
[...]
Karosserie montieren ist ein SubContainer
[usw...]
ich brauche in der Anwendung nun zugriff auf die FensterFarbe, von
denen es wie gesagt 0-4 geben kann.
P.S.:
Ich kann die Antwort des Services nicht ändern/anpassen, ich muss den kommenden json string nutzen.
@ Witte - die Idee mit dem VisitorPattern ist interessant.
Jedoch habe ich es entweder Missverstanden, oder es ist für meinen Ansatz nicht hilfreich. Der Kerngedanke des Patterns ist es ja, den Verarbeitungsalgorithmus von Objekten zu trennen (IMO)
Jedoch will ich nichts verarbeiten, sondern möglichst zuverlässig und schnell an einzelne Eigenschaften der SubObjekte herankommen.
Ich versteh es vermutlich immer noch nicht... (und evtl. bin ich nicht der Einzige..)
Worum geht es Dir denn? Was meinst Du mit "schnell und zuverlässig an Eigenschaften" kommen?
Geht es Dir um die Serialiserung der Json-Antwort, oder willst Du den Wert haben?
Reden wir hier von einer rekursiven Herarchie und ein Container ist das gleiche wie ein SubContainer, oder sind das zwei verschiedene Objekte(/Klassen) ?
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Hallo Abt,
vielen Dank vorab für deine Mühen.
Worum geht es Dir denn?
Was meinst Du mit "schnell und zuverlässig an Eigenschaften" kommen?
Geht es Dir um die Serialisierung der Json-Antwort, oder willst Du den Wert haben?
Reden wir hier von einer rekursiven Hierarchie und ein Container ist das gleiche wie ein SubContainer, oder sind das zwei verschiedene Objekte/Klassen) ?
Mir geht es darum, mit möglichst wenig Aufwand auf Elemente und ihre Werte innerhalb der "Produktionskette" zugreifen zu können.
Ich versuche es nochmal anders:
Gegeben sei diese Struktur:
Container C
C.Name
C.ID
C.SubContainer
SubContainer SC
SC.Name = SC1
SC.ID
SC.[...]
SC.SubContainerEigenschaftenListe<SubContainerEigenschaft>
SubContainerEigenschaft SCE_Name
SCE.Wert
SCE.[...]
SCE.SubContainerEigenschaftDeffinitionsListe<SubContainerEigenschaftDeffinition>
SubContainerEigenschaftDeffinition SCED
SCED.Typ = String
SubContainerEigenschaft SCE_Datum
SCE.Wert
SCE.[...]
SCE.SubContainerEigenschaftDeffinitionsListe<SubContainerEigenschaftDeffinition>
SubContainerEigenschaftDeffinition SCED
SCED.Typ = Date
SubContainerEigenschaft SCE_Ergebnis
SCE.Wert
SCE.[...]
SCE.SubContainerEigenschaftDeffinitionsListe<SubContainerEigenschaftDeffinition>
SubContainerEigenschaftDeffinition SCED
SCED.Typ = Double
SubContainer SC
SC.Name = SC2
SC.ID
SC.[...]
SC.SubContainerEigenschaftenListe<SubContainerEigenschaft>
SubContainerEigenschaft SCE_Name
SCE.Wert
SCE.[...]
SCE.SubContainerEigenschaftDeffinitionsListe<SubContainerEigenschaftDeffinition>
SubContainerEigenschaftDeffinition SCED
SCED.Typ = String
SubContainerEigenschaft SCE_Datum
SCE.Wert
SCE.[...]
SCE.SubContainerEigenschaftDeffinitionsListe<SubContainerEigenschaftDeffinition>
SubContainerEigenschaftDeffinition SCED
SCED.Typ = Date
SubContainerEigenschaft SCE_Ergebnis
SCE.Wert
SCE.[...]
SCE.SubContainerEigenschaftDeffinitionsListe<SubContainerEigenschaftDeffinition>
SubContainerEigenschaftDeffinition SCED
SCED.Typ = Double
[usw]
Wie komme ich möglichst flexibel an die SubContainerEigenschaft Name des Elementes SC2, ohne die gesammte Kette iterieren zu müssen?
Also egal was Du machst: hellsehen wird Dein Code auch nicht können.
Die Eierlegende-Wollmilchsau gibts nicht 😉
Du kannst Dir natürlich eine Reflection Methode bauen, damit Du zB schreiben kannst
MyReflectionMethods.GetPropValue("SubContainers.Name", "SC2")
Ist dann einfach - aber halt nicht flexibel.
Ansonsten würde ich mir eben ganz simpel ein paar Erweiterungsmethoden bauen, die das für mich abstrahieren.
Kann man super über funktionale Umsetzung, Expression Tree und Co mit wenig Code umsetzen.
Ich hab aktuell was ähnliches vor mir; geht um Produktionsanlagen, die Produktionslinien haben, und darin wiederum Maschinen, deren Bauteile und Eigenschaften.
Also auch eine "tiefere Hierarchie" - aber da ist ganz simpel eine Schleife drüber auf Linq-Basis bzw. die Dictionaries für den Direktzugriff.
Reicht völlig aus, ist sauber testbar und für jeden ohne Black Magic erweiter/wartbar.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code