Derzeit verwenden wir Entity Framework als ORM für einige Webanwendungen. Bis jetzt hat es uns gut gepasst, da alle unsere Daten in einer einzigen Datenbank gespeichert sind. Wir verwenden das Repository-Muster und verfügen über Dienste (die Domänenschicht), die diese verwenden, und geben die EF-Entitäten direkt an die ASP.NET MVC-Controller zurück.
Es besteht jedoch die Anforderung, eine Drittanbieter-API (über einen Webdienst) zu verwenden, die uns zusätzliche Informationen liefert, die sich auf den Benutzer in unserer Datenbank beziehen. In unserer lokalen Benutzerdatenbank speichern wir eine externe ID, die wir der to-API zur Verfügung stellen können, um zusätzliche Informationen zu erhalten. Es sind eine ganze Reihe von Informationen verfügbar, aber der Einfachheit halber bezieht sich eine davon auf das Unternehmen des Benutzers (Name, Manager, Raum, Berufsbezeichnung, Standort usw.). Diese Informationen werden an verschiedenen Stellen in unseren Web-Apps verwendet - im Gegensatz zur Verwendung an einem einzigen Ort.
Meine Frage ist also, wo ist der beste Ort, um diese Informationen zu füllen und darauf zuzugreifen? Da es an verschiedenen Orten verwendet wird, ist es nicht wirklich sinnvoll, es auf Ad-hoc-Basis abzurufen, wo immer wir es in der Webanwendung verwenden. Daher ist es sinnvoll, diese zusätzlichen Daten von der Domänenschicht zurückzugeben.
Mein erster Gedanke war nur, eine Wrapper-Modellklasse zu erstellen, die die EF-Entität (EFUser) und eine neue 'ApiUser'-Klasse mit den neuen Informationen enthält - und wenn wir einen Benutzer erhalten, erhalten wir den EFUser und dann den zusätzlichen Informationen aus der API und füllen Sie das ApiUser-Objekt. Dies ist zwar in Ordnung, um einzelne Benutzer zu erhalten, fällt jedoch um, wenn mehrere Benutzer abgerufen werden. Wir können die API nicht aufrufen, wenn wir eine Liste von Benutzern erhalten.
Mein zweiter Gedanke war nur, der EFUser-Entität, die den ApiUser zurückgibt, eine Singleton-Methode hinzuzufügen und sie bei Bedarf einfach zu füllen. Dies löst das oben genannte Problem, da wir nur dann darauf zugreifen, wenn wir es benötigen.
Oder der letzte Gedanke war, eine lokale Kopie der Daten in unserer Datenbank zu behalten und sie mit der API zu synchronisieren, wenn sich der Benutzer anmeldet. Dies ist nur ein minimaler Aufwand, da es sich nur um einen Synchronisierungsprozess handelt - und wir haben nicht den Aufwand, sie zu treffen die DB und API jedes Mal, wenn wir Benutzerinformationen erhalten möchten. Dies bedeutet jedoch, dass die Daten an zwei Orten gespeichert werden und dass die Daten für jeden Benutzer, der sich eine Weile nicht angemeldet hat, veraltet sind.
Hat jemand Ratschläge oder Vorschläge, wie man mit solchen Szenarien am besten umgeht?
quelle
it's not really sensible to fetch it on an ad-hoc basis
-- Warum? Aus Leistungsgründen?Antworten:
Dein Fall
In Ihrem Fall sind alle drei Optionen realisierbar. Ich denke, dass die beste Option wahrscheinlich darin besteht, Ihre Datenquellen an einem Ort zu synchronisieren, den die asp.net-Anwendung nicht einmal kennt. Vermeiden Sie also jedes Mal die beiden Abrufe im Vordergrund und synchronisieren Sie die API stillschweigend mit der Datenbank. Wenn dies in Ihrem Fall eine praktikable Option ist, sage ich, tun Sie es.
Eine Lösung, bei der Sie den Abruf "einmal" durchführen, wie es die andere Antwort vorschlägt, scheint nicht sehr praktikabel zu sein, da die Antwort nirgendwo beibehalten wird und ASP.NET MVC den Abruf nur für jede Anforderung immer wieder vornimmt.
Ich würde den Singleton meiden, ich denke nicht, dass es aus vielen der üblichen Gründe überhaupt eine gute Idee ist.
Wenn die dritte Option nicht realisierbar ist, besteht eine Option darin, sie verzögert zu laden. Das heißt, eine Klasse soll die Entität erweitern und die API nach Bedarf treffen . Das ist jedoch eine sehr gefährliche Abstraktion, da es sich um einen noch magischeren und nicht offensichtlichen Zustand handelt.
Ich denke, es läuft wirklich auf mehrere Fragen hinaus:
Ein oder zwei Worte zur Trennung von Bedenken
Gestatten Sie mir, gegen das zu argumentieren, was Bobson hier über die Trennung von Bedenken sagt. Letztendlich verstößt das Einfügen dieser Logik in solche Entitäten ebenso gegen die Trennung von Bedenken.
Ein solches Repository verletzt die Trennung von Bedenken ebenso schlimm, indem es die präsentationszentrierte Logik in die Geschäftslogikschicht einfügt. Ihr Repository ist sich jetzt plötzlich der präsentationsbezogenen Dinge bewusst, z. B. wie Sie den Benutzer in Ihren asp.net mvc-Controllern anzeigen.
In dieser verwandten Frage habe ich nach dem direkten Zugriff auf Entitäten von einem Controller aus gefragt. Gestatten Sie mir, dort eine der Antworten zu zitieren:
(Lesen Sie den Rest der Antwort, es ist wirklich schön imo).
Es ist naiv, die Tatsache zu ignorieren, dass es eine Datenbank gibt - es gibt eine Datenbank, und egal wie schwer Sie das abstrahieren möchten, es geht nirgendwo hin. Ihre Anwendung wird sich bewusst sein die Datenquelle. Sie können es nicht im laufenden Betrieb austauschen. ORMs sind nützlich, aber sie lecken aufgrund der Kompliziertheit des von ihnen gelösten Problems und aus zahlreichen Leistungsgründen (z. B. Select n + 1).
quelle
Bei einer ordnungsgemäßen Trennung der Bedenken sollte nichts über der Entity Framework / API-Ebene überhaupt erkennen, woher die Daten stammen. Sofern der API-Aufruf nicht teuer ist (in Bezug auf Zeit oder Verarbeitung), sollte der Zugriff auf Daten, die ihn verwenden, genauso transparent sein wie der Zugriff auf Daten aus der Datenbank.
Der beste Weg, dies zu implementieren, besteht darin, dem
EFUser
Objekt zusätzliche Eigenschaften hinzuzufügen, die die API-Daten nach Bedarf verzögern. Etwas wie das:Extern wird bei der ersten Verwendung
CompanyName
oderJobTitle
bei der ersten Verwendung ein einzelner API-Aufruf (und damit eine kleine Verzögerung) ausgeführt. Alle nachfolgenden Aufrufe bis zur Zerstörung des Objekts sind jedoch genauso schnell und einfach wie der Datenbankzugriff.quelle
Eine Idee ist, ApiUser so zu ändern, dass nicht immer die zusätzlichen Informationen vorhanden sind. Stattdessen legen Sie eine Methode auf ApiUser, um sie abzurufen:
Sie können dies auch geringfügig ändern, um das verzögerte Laden zusätzlicher Daten zu verwenden, sodass Sie UserExtraData nicht aus dem ApiUser-Objekt extrahieren müssen:
Auf diese Weise werden bei einer Liste die zusätzlichen Daten standardmäßig nicht abgerufen. Sie können aber trotzdem darauf zugreifen, während Sie die Liste durchlaufen!
quelle