2013-03-21 12 views
9

erstellt Ich habe das folgende Verhalten bemerkt und ich frage mich, ob jemand erklären kann, warum es geschieht und wie kann verhindert werden.ASP.NET MVC liest Eigenschaften, wenn das Objekt

In meinen partiellen Klassen habe ich verschiedene Nur-Lese-Eigenschaften hinzugefügt, die in der Datenbank nicht vorhanden sind. Wenn das Objekt erstellt wird, wird auf diese Eigenschaften zugegriffen, bevor wir zur Create-Methode des Controllers gelangen. Auf Eigenschaften, die nur mit get; set; deklariert sind, wird jedoch nicht zugegriffen.

Um dies näher auszuführen, sehr einfache Beispiele, wenn ich die folgenden Eigenschaften haben:

public bool getBoolProperty { 
    get { 
     return true; 
    } 
} 
public bool getSetBoolProperty { 
    get; set; 
} 

Wenn ich setzte Haltepunkte auf den Eigenschaften dann, wenn das Objekt erstellt wird der Haltepunkt für die erste Eigenschaft getroffen wird, aber nicht der Zweite. Wenn ich jedoch eine Methode habe:

public bool getBoolProperty() { 
    return true; 
} 

dann wird nicht darauf zugegriffen.

Ich habe alle möglichen Variationen ausprobiert und Anmerkungen

// empty set 
public bool getBoolProperty { 
    get { 
     return true; 
    } 
    set {} 
} 

// not mapped attribute 
[NotMapped] 
public bool getBoolProperty { 
    get { 
     return true; 
    } 
} 

// getting private variable 
private bool _boolProperty = true; 
public bool getPrivateBoolProperty { 
    get { 
     return _boolProperty; 
    } 
} 

Ich habe versucht virtual die Eigenschaften zu erklären, aber alle Variationen, mit Ausnahme der get; set; Vielfalt, zugegriffen werden, wenn das Objekt erstellt wird. Dieses Verhalten tritt auch für Integer-Eigenschaften

public virtual int getIntProperty { 
    get { 
     return 1; 
    } 
} 

und Datum/Zeit Eigenschaften,

public virtual DateTime getDateProperty { 
    get { 
     return DateTime.Now; 
    } 
} 

aber nicht für String-Eigenschaften

public string getStringProperty { 
    get { 
     return "Hello String"; 
    } 
} 

oder eine andere Einheit Eigenschaften

public Item getItem { 
    get { 
     return new Item(); 
    } 
} 

Das Problem em ich habe, ist, dass einige dieser Eigenschaften eine gewisse Logik beinhalten können, die Zugriff auf die Datenbank zB

public bool HasChildren { 
    get { 
     return this.Children !== null && this.Children.Count > 0; 
    } 
} 

, die zum Zeitpunkt der Erstellung benötigen könnten, nicht das Unternehmen haben.

Offensichtlich kann ich das umgehen, indem ich alles zu einer Methode mache, aber ich wäre interessiert zu wissen, warum ASP.NET MVC auf diese Eigenschaften bei der Objekterstellung zugreift (eine Art interne Validierung vielleicht), und würde mich interessieren zu wissen wenn es irgendwelche Methoden gibt, dies zu verhindern, möglicherweise durch eine Anmerkung, die ich nicht gesehen habe.

Mein Projekt ist Datenbank zuerst, C#, EF 4.1, MVC

bearbeiten

ich auch darauf hinweisen, sollte ich POCO Entitäten bin mit und die Datenbank über gespeicherte Prozeduren/Funktion importiert zugreifen.

Ein Gedanke kam mir der Gedanke ist, dass diese Eigenschaften im Rahmen des Change Tracking-System wie diskutiert here zugegriffen wird. Es scheint, dass wahrscheinlich ein Schnappschuss von dem neu erstellten Gegenstand gemacht wird. Ich versuchte ausgeschaltet Proxy-Erstellung

dbContext.ContextOptions.ProxyCreationEnabled = false; 

aber die Eigenschaften sind nach wie vor auf die Schaffung zugegriffen zu werden.

bearbeiten 20130322

Nach Vorschlag des @ ladislavmrnka die Stack-Trace zu erforschen ich diese bekam:

at System.ComponentModel.ReflectPropertyDescriptor.GetValue(Object component) 
at System.Web.Mvc.AssociatedMetadataProvider.<>c__DisplayClassb.<GetPropertyValueAccessor>b__a() 
at System.Web.Mvc.ModelMetadata.get_Model() 
at System.Web.Mvc.DataAnnotationsModelValidator.<Validate>d__1.MoveNext() 
at System.Web.Mvc.ModelValidator.CompositeModelValidator.<Validate>d__5.MoveNext() 
at System.Web.Mvc.DefaultModelBinder.OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext) 
at System.Web.Mvc.DefaultModelBinder.BindComplexElementalModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Object model) 
at System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
at System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
at System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) 
at System.Web.Mvc.ControllerActionInvoker.GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor) 
at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) 
at System.Web.Mvc.Controller.ExecuteCore() 
at System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) 
at System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) 
at System.Web.Mvc.MvcHandler.<>c__DisplayClass6.<>c__DisplayClassb.<BeginProcessRequest>b__5() 
at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass1.<MakeVoidDelegate>b__0() 
at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) 
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.End() 
at System.Web.Mvc.MvcHandler.<>c__DisplayClasse.<EndProcessRequest>b__d() 
at System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f) 
at System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action) 
at System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) 
at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) 
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() 
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) 

Darin finden Sie die Anrufe zu einem Prüfer oder zwei bemerken. Als Test änderte ich meine Bool-Eigenschaft auf eine Nullable-Bool Eigenschaft:

public bool? getBoolProperty { 
    get { 
     return true; 
    } 
} 

Dieses Mal ist die Eigenschaft nicht zugegriffen wurde, wenn das Objekt erstellt wurde. Dies ist mein gewünschtes Verhalten, aber ich möchte nicht alle meine benutzerdefinierten Eigenschaften ändern müssen, um NULL-fähig zu sein, so dass meine Frage jetzt wird ...

Gibt es eine Möglichkeit, das Framework nicht zu validieren ein Eigentum? Vielleicht über ein Attribut. This answer fast beantwortet die Frage, aber da ich Datenbank zuerst verwende, scheint ich nicht eine ValidateOnSaveEnabled Eigenschaft zu deaktivieren. Vielleicht muss ich meine Modelle noch einmal besuchen.

+0

Der Zugriff auf die Eigenschaften ist wahrscheinlich eine Mapping- oder Reflektionssache. Wie auch immer, Sie sollten die Eigenschaften mit [NotMapped] kommentieren. –

+0

So stoppt der Debugger nicht nur, wenn Sie Auto-Eigenschaft verwenden? Der Debugger stoppt nicht bei automatisch implementierten Eigenschaften, es sei denn, Sie verwenden einen [Trick] (http://stackoverflow.com/questions/4408110/debugging-automatic-properties). Für andere Eigenschaften starten Sie, indem Sie den Aufruf-Stack untersuchen, um herauszufinden, was den Zugriff verursacht. –

+0

@LadislavMrnka, verwende ich Web Developer Express, die leider kein Breakpoints-Fenster hat. Netter Tipp auf dem Call-Stack obwohl – Webbie4

Antwort

1

Wie bei den meisten EF-Problemen liegt die Antwort bei Ansichtsmodellen.

Da die meisten Eigenschaften, auf die zugegriffen wurde, erst relevant waren, als das Modell erstellt und in der db gespeichert wurde, erstellte ich ein Ansichtsmodell speziell für die Create-Ansicht, das nur die absolute Mindestanzahl an Eigenschaften zum Erstellen enthielt das Model. Ich habe die Create-Methode des Controllers geändert, um mein neues Ansichtsmodell zu akzeptieren, und voila, beim Erstellen dieses neuen Modells gab es keine Zugriffe auf irrelevante Eigenschaften des Hauptmodells.

Die Antwort auf meine ursprüngliche Frage scheint zu sein, dass das Entitätsframework die Validierung für alle nicht nullbaren Skalareigenschaften durchführt, wenn ein Objekt erstellt wird, und eine Möglichkeit, dies zu vermeiden, ist wie oben erläutert.

+0

Dies ist eigentlich ein MVC-Punkt und nicht ein EF-Punkt. MVC führt den ModelBinder und als Teil davon Validierungslogik aus. Es ist die Validierungslogik von MVC, die versucht, die Eigenschaft zu lesen. Ihr Punkt hier ist jedoch korrekt, Sie sollten ViewModels immer für MVC-Ansichten verwenden und nie direkt an Ihre Entitäten binden (Ansichtsmodelle sollten auch keine Entitäten enthalten) Um sicherzustellen, dass Ihre Sammlungen in Entitäten nicht null sind, Sie können sie als Hash-Sets in Ihrem Konstruktor initialisieren. Dies gewährleistet, dass Ihre EF-Modelle in einem eigenständigen Kontext arbeiten. – stevenrcfox

Verwandte Themen