Frage

Ich benutze das "Stub -Technik" zu aktualisieren Meine PoCOs (in einem abgelösten Kontext, ASP.NET MVC).

Dies ist der Code, den ich derzeit in meinem Controller habe (der funktioniert):

[HttpPost]
public ActionResult Edit(Review review)
{
   Review originalReview = _userContentService.FindById(review.PostId) as Review;
   var ctx = _unitOfWork as MySqlServerObjectContext;
   ctx.ApplyCurrentValues("MyEntities.Posts", review);
   _unitOfWork.Commit();
   // ..snip - MVC stuff..
}

Wie Sie sehen können, gibt es überall Codegeruch. :)

Ein paar Punkte:

  1. Ich verwende die Abhängigkeitsinjektion (Schnittstelle) für im Grunde genommen alles
  2. Ich verwende die Einheit des Arbeitsmusters, um ObjectContext zu abstrakt
  3. Derzeit mein Iunitofwork Die Schnittstelle hat nur 1 Methode: void Commit();
  4. Controller haben IUserContentService und IUnitOfWork Injektion von di
  5. IUserContentService Anrufe Find in Repositories, die die verwenden ObjectContext.

Dies sind zwei Dinge, die ich mit meinem obigen Code nicht mag:

  1. Ich möchte das nicht werfen Iunitofwork wie MySqlServerObjectContext.
  2. Ich möchte nicht ApplyCurrentValues

Ich möchte im Grunde genommen, dass mein Code so aussieht:

[HttpPost]
public ActionResult Edit(Review review)
{
   _userContentService.Update(review);
   _unitOfWork.Commit();
   // ..snip - MVC stuff..
}

Irgendwelche Ideen, wie ich das machen kann? (oder etwas ähnliches).

Ich habe bereits Smarts, um den Namen des Entity -Sets basierend auf dem Typ (Kombination von Generika, Pluralisation) zu erarbeiten. Machen Sie sich also nicht allzu viel Sorgen.

Aber Ich frage mich, wo der beste Ort zu setzen ist ApplyCurrentValues ist? Es scheint nicht angemessen, es in die zu setzen IUnitOfWork Schnittstelle, wie dies ein Anliegen von Persistenz (EF) ist. Aus dem gleichen Grund gehört es nicht zum Dienst. Wenn ich es in meine stecke MySqlServerObjectContext Klasse (macht Sinn), wo würde ich das nennen, da nichts direkt Zugriff auf diese Klasse hat - sie wird über DI injiziert, wenn etwas anfordert IUnitOfWork.

Irgendwelche Gedanken?

BEARBEITEN

Ich habe eine Lösung unten mit der Stub -Technik, aber das Problem ist, wenn ich die Entität, die ich vorher aktualisiere, abgerufen habe. Es bringt eine Ausnahme aus und gibt an, dass ein Entität mit diesem Schlüssel bereits vorhanden ist.

Was macht sinnvoll, obwohl ich nicht sicher bin, wie kann das beheben?

Muss ich "prüfen, ob die Entität bereits angehängt ist, wenn nicht, fügen Sie es an?"

Können EF4 -Experten da draußen helfen?

BEARBEITEN

Nevermind - Die Lösung gefunden, siehe Antwort unten.

War es hilfreich?

Lösung

Es hat es herausgefunden - war nicht einfach, also werde ich versuchen, das Beste zu erklären, was ich kann. (für diejenigen, die sich interessieren)

Controller Relevanter Code:

// _userContentService is IUserContentService
_userContentService.Update(review);

Mein Controller ruft also eine Methode auf, die genannt wird Update an IUserContentService, durch die stark typen Review Objekt.

Benutzerinhaltsdienst relevanter Code

public void Update(Post post)
{
   // _userContentRepository is IPostRepository
   _userContentRepository.UpdateModel(post);
}

Mein Service ruft also eine Methode an, die genannt wird UpdateModel an IPostRepository, durch die stark typen Review Objekt.

Jetzt ist hier der schwierige Teil.

Ich habe tatsächlich Keine spezifischen Repositories. Ich habe ein Generisches Repository genannt GenericRepository<T> : IRepository<T>, was behandelt all die verschiedenen Repositorys.

Also, wenn etwas ein Anfragen a IPostRepository (Was mein Dienst tat), di würde es a geben GenericRepository<Post>.

Aber jetzt gebe ich es a PostRepository:

public class PostRepository : GenericRepository<Post>, IPostRepository
{
   public void UpdateModel(Post post)
   {
      var originalPost = CurrentEntitySet.SingleOrDefault(p => p.PostId == post.PostId);
      Context.ApplyCurrentValues(GetEntityName<Post>(), post);
   }
}

Und weil die Klasse abgeleitet aus GenericRepository, Es erbt alle Kern -Repository -Logik (Finden, Hinzufügen usw.).

Zuerst habe ich versucht, das auszudrücken Updatemodel Code in der GenericRepository Klasse selbst (und dann hätte ich dieses spezielle Repository nicht benötigt), aber das Problem ist die Logik, um die vorhandene Entität abzurufen GenericRepository<T> würde nichts wissen.

Aber das Endergebnis ist das Nähen ist tief in den Tiefen der Datenschicht versteckt, und am Ende habe ich einen wirklich sauberen Controller.

BEARBEITEN

Diese "Stub -Technik" funktioniert auch:

public void UpdateModel(Post post)
{
   var stub = new Review {PostId = post.PostId};
   CurrentEntitySet.Attach(stub);
   Context.ApplyCurrentValues(GetEntityName<Post>(), post);
}

Aber das Problem ist, weil Post ist abstrakt, ich kann nicht instanziieren und müsste daher die Art des Posts überprüfen und Stubs für erstellen jeder einzelne abgeleiteter Typ. Nicht wirklich eine Option.

Bearbeiten 2 (letztes Mal)

Okay, habe die "Stub -Technik" mit abstrakten Klassen gearbeitet, so dass jetzt das Problem der Parallelität gelöst wird.

Ich habe meinem einen generischen Typparameter hinzugefügt Updatemodel Methode und das Special New () Einschränkung.

Implementierung:

public void UpdateModel<T>(T post) where T : Post, new()
{
   var stub = new T { PostId = post.PostId };
   CurrentEntitySet.Attach(stub);
   Context.ApplyCurrentValues(GetEntityName<Post>, post);
}

Schnittstelle:

void UpdateModel<T>(T post) where T : Post, new();

Dies hindert mich daran, die Art von T manuell herauszufinden, verhindert Probleme mit Parallelität und verhindert auch eine zusätzliche Reise in die DB.

Ziemlich groovig.

Bearbeiten 3 (Ich dachte, das letzte Mal war das letzte Mal)

Die obige "Stub -Technik" funktioniert, aber wenn ich das Objekt vorher abrufe, wird eine Ausnahme ausgelöst, in der eine Entität mit diesem Schlüssel bereits im OSM vorhanden ist.

Kann jemand raten, wie man damit umgeht?

Bearbeiten 4 (ok - das ist es!)

Dank dieser Antwort fand ich die Lösung, also Antwort: Ist es möglich, zu überprüfen, ob ein Objekt bereits an einen Datenkontext im Entity Framework angeschlossen ist?

Ich hatte versucht, "zu überprüfen, ob die Entität angehängt ist" mit dem folgenden Code:

ObjectStateEntry entry;
CurrentContext.ObjectStateManager.TryGetObjectStateEntry(entity, out entry);

Aber es kehrte immer zurück Null, Selbst wenn ich das OSM erkundete, konnte ich meine Entität dort mit demselben Schlüssel sehen.

Aber dieser Code funktioniert:

CurrentContext.ObjectStateManager.TryGetObjectStateEntry(CurrentContext.CreateEntityKey(CurrentContext.GetEntityName<T>(), entity), out entry)

Vielleicht hatte das OSM Schwierigkeiten, den Entitätschlüssel zu finden, der weiß, weil ich Pure Poco verwende.

Oh und eine andere Sache, die ich hinzugefügt habe - damit ich für jede Entität kein bestimmtes Repository hinzufügen muss, habe ich ein Attribut namens erstellt. "EntityKey"(öffentliches Eigentumattribut).

Alle POCOs müssen 1 öffentliches Anwesen mit diesem Attribut dekorieren, oder ich mache eine Ausnahme in mein Repository -Modul.

Mein generisches Repository sucht also nach dieser Eigenschaft, um den Stub zu erstellen/einzurichten.

Ja - es verwendet Reflexion, aber es ist clevere Reflexion (Attributbasiert) und ich verwende bereits Reflexion für die Plularisierung von Entitätsnamen aus T.

Wie auch immer, Problem gelöst - alle funktionieren jetzt gut!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top