Laden...

DocumentDB Dokument zurückgeben ohne es zu kennen

Erstellt von ByteDevil vor 4 Jahren Letzter Beitrag vor 4 Jahren 1.490 Views
ByteDevil Themenstarter:in
132 Beiträge seit 2013
vor 4 Jahren
DocumentDB Dokument zurückgeben ohne es zu kennen

verwendetes Datenbanksystem: CosmosDB

Hallo,

ich schreibe gerade eine REST-API die später dann in Azure laufen und den Inhalt einer CosmosDB als JSON zurückgeben soll. Die API kann bestimmte Filter in Form eines Query-Strings in der URL entgegen nehmen und formt daraus einen Linq-Ausdruck, der dann mittels des Microsoft.Azure.Documents.Client eine Datenbankabfrage macht. Jedes dieser Datenbankobjekte ist recht groß und die DB wird durch ein anderes Tool gefüttert, welches den Datentyp aus dem serialisiert wird immer genau kennt.
Nun kann es sein, dass sich die Struktur der Daten vielleicht einmal leicht ändern wird. Passiert das, möchte ich nicht jedes mal an den Webservice gehen und das DB model updaten, damit die neu hinzugekommenen Daten mit deserialisiert werden. Ich möchte das mein Webservice nur von den Properties weiß, nach denen mit einem Query-String gesucht werden können soll. Zurückgeben möchte ich aber immer alles von dem Objekt. So müsste ich dann nur was an dem Webservice ändern, wenn eine neue Filteroption her soll.
Ist das verständlich ausgedrückt?

EDIT: Nochmal ein kleines Beispiel:

class Person
    {
        public string Id { get; set; }
        public string Vorname { get; set; }
        public string Nachname { get; set; }
        public string Adresse { get; set; }
        public int Alter { get; set; }
        public bool Geschlecht { get; set; }
    }

Tool A definiert diese Struktur und füttert die DB auch direkt.

Tool B weiß nur das da:

class PersonFlat
    {
        public string Id { get; set; }
        public string Vorname { get; set; }
        public int Alter { get; set; }
        public bool Geschlecht { get; set; }
    }

Und das auch nur, weil Tool B die Datenbankabfrage nach Id, Vorname, Alter und Geschlecht machen können soll. Dennoch soll Tool B dann trotzdem ALLES als JSON aussprucken können. Geht das?

16.833 Beiträge seit 2008
vor 4 Jahren

"Geht das?" ist eine Frage, die man immer mit Ja beantworten kann.
Alles nur eine Frage des Aufwands.

Ich möchte das mein Webservice nur von den Properties weiß, nach denen mit einem Query-String gesucht werden können soll. Zurückgeben möchte ich aber immer alles von dem Objekt.

Das ist eine gegensätzliche Anforderung. Kann so nicht funktionieren.

Du kannst natürlich nur die Elemente gegen die Datenbank abfragen, die im Query mitkommen - aber nur die werden dann eben auch geladen; nicht alle.

OData kann das von Haus aus, wenn man IQueryable verwendet.
IQueryable wird aber derzeit nicht vom CosmosDB SDK unterstützt.

Prinzipiell musst Du dieses Verhalten daher selbst ausprogrammieren.

ByteDevil Themenstarter:in
132 Beiträge seit 2013
vor 4 Jahren

Das ist eine gegensätzliche Anforderung. Kann so nicht funktionieren.

Wie meinst du das? Das ist doch als würde ich dich bitten mir aus lauter Koffern den zu geben, auf dem mein Name drauf steht. Dafür musst du wissen was ein Koffer ist, das ein Name darauf stehen kann und als Query teile ich dir meinen Namen mit. Du gibst mir den Koffer ohne zu wissen was darin ist und ob da überhaupt was drin ist. Wieso ist das so abwegig?

Du kannst natürlich nur die Elemente gegen die Datenbank abfragen, die im Query mitkommen - aber nur die werden dann eben auch geladen; nicht alle.

Genau das ist mein Problem...bei der Deserialisierung muss ich ja den richtigen Typ kennen. Gebe ich im obigen Beispiel PersonFlat an, wird nur deserialisiert was PeronFlat kennt. Der Rest wird verworfen. Document DB speichert doch auch alles als JSON, oder? Kann ich nicht einfach nur irgendwie den json string bekommen? Oder ich mache eine Abfrage über PersonFlat und merke mir die ID's und hole mir dann jede Person über die ID...aber auch da brauche ich ja wieder eine Klasse zum deserialisieren...

16.833 Beiträge seit 2008
vor 4 Jahren

Wie meinst du das?

So wie ich Dich verstanden habe: Du willst nur ein Teil laden, aber alles zurück geben.

Passiert das, möchte ich nicht jedes mal an den Webservice gehen und das DB model updaten, damit die neu hinzugekommenen Daten mit deserialisiert werden.

Wenn Du das gleiche Modell für das Speichern der Daten verwendest und für das Abfragen, dann hat eine Schemaänderung direkte Auswirkungen auf die Abfrage.
Im Endeffekt ein Resultat von [Artikel] Drei-Schichten-Architektur

Genau das ist mein Problem...bei der Deserialisierung muss ich ja den richtigen Typ kennen.

Von welcher Serialisierung sprichst Du? Ist PersonFlat ein API Modell? Die Bezeichner sind unüblich.
Es gibt Entitäten, das sind Darstellungen von Datenbanken, dann Business Modelle für die Logik und dann gibt es eben zB. bei APIs Input Modelle für die Queries und Response Modelle für die Antwort.

Serialisieren müsste man hier prinzipiell nichts.
Man würde das eher mit einem Expression Visitor machen, wenn Du schon mit Linq arbeitest; aber das kommt eben drauf an.

Du kannst auch das gesamte Datenbankmodell laden und nur ein Teil zurück geben in Form von einem entsprechenden Response Modell.
Werden halt nur die Properties in das Modell übertragen, die existieren. Kann man manuell machen oder via Reflection (zB AutoMapper).

Mit Json einer DocumentDB hast Du _eigentlich _nichts zutun; kann man machen, aber nur sehr selten sinnvoll.
Man würde das Modell laden - kein Json; jedenfalls normalerweise.

Oder ich stehe auf dem Schlauch und verstehe Dich völlig falsch.

ByteDevil Themenstarter:in
132 Beiträge seit 2013
vor 4 Jahren

So wie ich Dich verstanden habe: Du willst nur ein Teil laden, aber alles zurück geben.

Ich will dem Webservice einfach so wenig wie nur möglich über die Datenstruktur bekannt machen, damit ich möglichst selten etwas an dem Webservice ändern muss.

Wenn Du das gleiche Modell für das Speichern der Daten verwendest und für das Abfragen, dann hat eine Schemaänderung direkte Auswirkungen auf die Abfrage.

Nein eben nicht. Wenn ich Personen mit den Vornamen [Hans, Henry, Heinrich] in der DB habe, ich mit PersonFlat nach Vornamen suche die mit H anfangen, kriege ich die drei zurück. Update ich den Datenbankeintrag und ergänze die Struktur der Daten noch mit dem Gewicht der drei personen, bekomme ich ja trotzdem wieder die drei zurück wenn ich den Query wiederhole. Und genau das will ich erreichen. Der Webservice soll quasie nicht wissen das die Personen auch über ein Gewicht verfügen...kann dem Service total egal sein, weil er eh nicht danach Filtern können soll. Für den Client der den API call gemacht hat, ist es aber vielleicht interessant wie viel die wiegen...daher soll er die Information bekommen wenn sie da ist.

16.833 Beiträge seit 2008
vor 4 Jahren

Ich will dem Webservice einfach so wenig wie nur möglich über die Datenstruktur bekannt machen, damit ich möglichst selten etwas an dem Webservice ändern muss.

Daher der Hinweis auf die Schichtentrennung und die Modelle.
Eine API ist technisch gesehe nichts anderes als eine Ansicht - und da hat man eben extra Modelle.
Das hat sich bewährt, ist üblich und empfohlen.

Der Webservice soll quasie nicht wissen das die Personen auch über ein Gewicht verfügen...kann dem Service total egal sein, weil er eh nicht danach Filtern können soll.

Für den Client der den API call gemacht hat, ist es aber vielleicht interessant wie viel die wiegen...daher soll er die Information bekommen wenn sie da ist.

Tut mir leid; verstehe ich nicht.
Der Client will also Informationen vom Service, die der Service nicht kennt, aber in der Datenbank vorhanden sind.
.....wat ? 🤔

ByteDevil Themenstarter:in
132 Beiträge seit 2013
vor 4 Jahren

Daher der Hinweis auf die Schichtentrennung und die Modelle.
Eine API ist technisch gesehe nichts anderes als eine Ansicht - und da hat man eben extra Modelle.
Das hat sich bewährt, ist üblich und empfohlen.

Okay, danke. Ich werde es mir ansehen.

Tut mir leid; verstehe ich nicht.
Der Client will also Informationen vom Service, die der Service nicht kennt, aber in der Datenbank vorhanden sind.
.....wat ? 👶

Ja 😄 Tatsächlich genau das^^ Naja stell dir vor du hast in Tool A (füttert die Datenbank) eine Klasse. Bleiben wir bei der Klasse Person von oben. Du entwickelst dieses Tool über Jahre ständig weiter (und nicht nur du alleine) und hin und wieder wird Person um eine Property erweitert. Dann musst du ja JEDES mal an den Webservice und ihm diese neue Property ja auch in PersonFlat implementieren...selbst wenn der Webservice selbst diese Property nie verwendet, weil danach nicht gefiltert werden soll. Einfach nur damit der Client sie dann mit in seinem JSON string hat... Das wirkt auf mich wie eine sehr blöde Lösung bei der mit Sicherheit bald was schief läuft weil es vergessen wird.

16.833 Beiträge seit 2008
vor 4 Jahren

Dann musst du ja JEDES mal an den Webservice und ihm diese neue Property ja auch in PersonFlat implementieren...selbst wenn der Webservice selbst diese Property nie verwendet, weil danach nicht gefiltert werden soll.

Richtig. Daher gibt es Versionierung von APIs.

Der Sinn von APIs ist, dass die API das Wissen über Struktur und Co hat - ansonsten kann sie ihre Aufgabe gar nicht erfüllen.
Ganz wichtig: Eine API kennt jedoch ihre Clients nicht.

Eine REST API kennt die Ressourcen - und Ressourcen haben Definitionen und Strukturen.
Die API kennt also die Struktur jedes Modells.

Das wirkt auf mich wie eine sehr blöde Lösung bei der mit Sicherheit bald was schief läuft weil es vergessen wird.

Einfach eine API zu entwickeln, die unwissend alles mögliche durchschleußt ist eine sehr blöde Lösung bei der mit Sicherheit bald was schief läuft - von Security und Client Breakes noch gar nicht gesprochen 😉

ByteDevil Themenstarter:in
132 Beiträge seit 2013
vor 4 Jahren

Hmmm okay aus der Sicht habe ich es noch gar nicht betrachtet...Also du würdest es schon so implementieren, dass die API immer geupdated werden muss?

16.833 Beiträge seit 2008
vor 4 Jahren

Sofern es eine REST API werden soll: auf alle Fälle.
Natürlich kann man eine REST API aber vortwärtskompatibel entwickeln. Bestes Beispiel sind hier alle Google APIs.
Allen voran mein Lieblungsbeispiel für sehr guten API Aufbau: Google Maps.

Es hat schon sein Grund, dass man sich Gedanken beim Aufbau einer API machen muss und das ein fortschrittliche, anspruchsvolle Aufgabe ist.
Einfach so vor sich her entwickeln "und mal schauen, wie sich das entwickelt" - das kann nur in die Hose gehen.

ByteDevil Themenstarter:in
132 Beiträge seit 2013
vor 4 Jahren

Okay, ich nehm's mir zu Herzen. Danke für deine Zeit 😃

16.833 Beiträge seit 2008
vor 4 Jahren

Falls Du Alternativen willst:

Mit gRPC statt REST hast Du einen Contract, der ähnlich wie REST über die Url versioniert wird.
Durch den Contract kannst Du die API Modelle aber leichter austauschen.

Mit GraphQL abstrahierst Du völlig den strukturellen Aufbau.
D.h. es gibt quasi Queries mit einer eigenen Abfragesprache und Mutations für Änderungen.
Das Backend muss braucht dazu einen Query Resolver (Schema), der völlig losgelöst von der Datenquelle ist.
Beim Query kann man explizit sagen, was man laden möchte, und was nicht. Der Client steuert das.

Ich vermute, dass GraphQL Deinen Anforderungen viel näher kommt als REST.