Mit MVC und fließend Nhibernate, wie kann ich bestätige einzigartige Felder auf meinem Viewmodel, bevor ich sie zu meinem Domain-Objekt binden und speichern?

StackOverflow https://stackoverflow.com/questions/1440440

Frage

Ich habe eine Website, wo ich Benutzer erlauben, neue Teil Datensätze zu erstellen. Ich versuche, den besten Weg, um herauszufinden, auf bestimmte Felder für Einzigartigkeit zu validieren. Ich möchte sicherstellen, dass jemand versucht nicht, einen Teil mit Part 1234 hinzufügen, wenn das Part auf einem anderen Teil ist bereits vorhanden.

Die Web-Anwendung ist für die Zuordnung meiner Objekte in die Datenbank Asp.net MVC mit fließend nHibernate verwenden. Ich verwende Castle Validierung auf meiner Ansicht Modelle für Dinge wie ValidateNonEmpty, ValidateRange usw. Soll ich die ValidateSelf Methode das Repository abzufragen, ob das teil~~POS=TRUNC zu sehen ist bereits vorhanden? Etwas fühlt sich nicht richtig über meine Repository auf der Ansichtsmodell verwenden.

Wäre es besser für mich, dass die Logik auf der Controller-Aktion zu platzieren? Das scheint nicht richtig, weil ich meine Viewmodel erwarten bereits an dem Punkt entwertet werden (während ModelBind).

Oder vielleicht seine keines der oben genannten. Vielen Dank für jede Hilfe auf diesem.

UPDATE Ok, nicht sicher, ob dies helfen wird, aber hier ist das, was meine speichert Aktion wie für ein typisches Aussehen Aktion erstellen in meinem Projekt:

public ActionResult Create(PartViewModel viewModel)
{
 //I think I'd like to know if its Valid by this point, not on _repository.Save
 if(ModelState.IsValid)
 {
    try
    {
        var part = _partCreateViewModelMap.MapToEntity(viewModel);

        _repository.Save(part);
        return Redirect("~/Part/Details/" + part.Id);
    }
    catch (Exception e)
    {
        // skip on down...
    }
 }

 // return view to edit 
 return View(viewModel);
}
War es hilfreich?

Lösung

Ich habe oft diese Frage gestellt. Meine Freunde waren besorgt darüber, ob sie den Datenzugriff vom Validator Code ausführen kann. Die Antwort ist einfach. Wenn Sie dies tun müssen, sollten Sie es tun. Normalerweise brauchen wir solche Kontrollen auf jeder Ebene der Abstraktion zu tun. Und nach allen Kontrollen sollten Sie bereit sein, eine Ausnahme zu fangen, verursacht durch einmalige Einschränkungsverletzung.

Andere Tipps

Wenn Sie eine eindeutige Einschränkung innerhalb der Datenbank definieren, warum dann nicht die Verantwortung delegieren zu prüfen, ob ein eindeutiger Wert existiert bereits in der Datenbank? Mit NHibernate können Sie die NHibernate.Exceptions.ISQLExceptionConverter-Schnittstelle verwenden, zu erfassen und zu transformieren im Zusammenhang bekannte Fehler Verletzung Zwang. Sie können auch NHibernate.Exceptions.IViolatedConstraintNameExtracter Implementierer (siehe NHibernate.Exceptions.TemplatedViolatedConstraintNameExtracter) erhalten an den schmuddeligen Details Ihrer Datenbank Ausnahme und verwandeln es in eine benutzerfreundliche Nachricht, Umpacken als Validierungs Ausnahme Ihres chosing und fangen sie in dem entsprechenden Controller.

Beispiel für einen schnellen, sehr spezifischen quick and dirty Ausnahme-Konverter von einem meiner Projekten:


Imports NHibernate
Imports NHibernate.Exceptions
Imports System.Data.SqlClient
Imports System.Data.Common

Namespace NHibernate

    Public Class ConstraintViolationExceptionConverter
        Implements ISQLExceptionConverter

        Public Function Convert(ByVal adoExceptionContextInfo As Global.NHibernate.Exceptions.AdoExceptionContextInfo) As System.Exception Implements Global.NHibernate.Exceptions.ISQLExceptionConverter.Convert

            Dim dbEx As DbException = ADOExceptionHelper.ExtractDbException(adoExceptionContextInfo.SqlException)

            If TypeOf dbEx Is SqlException Then
                Dim sqlError As SqlException = DirectCast(dbEx, SqlException)

                Select Case sqlError.Number
                    Case 547
                        Return New ConstraintViolationException(adoExceptionContextInfo.Message, adoExceptionContextInfo.SqlException)

                End Select

            End If

            Return SQLStateConverter.HandledNonSpecificException(adoExceptionContextInfo.SqlException, adoExceptionContextInfo.Message, adoExceptionContextInfo.Sql)

        End Function


    End Class

End Namespace

projektierter durch das web.config/nhibernate-configuration/session-factory Eigenschaftselement:


<property name="sql_exception_converter">csl.NHibernate.ConstraintViolationExceptionConverter, csl</property>

Edit: Sollte wohl erwähnen, dass die Konverter-Schnittstelle in neueren Versionen von NHibernate geändert hat, ist die Schnittstelle aus diesem Beispiel aus NHibernate.dll v2.1.0.4000

ich in der Regel eine Dienstschicht zwischen meinem Controller und Repositories setzen.
Die Service-Schicht würde dann behandelt die Validierung und Anrufe in das Repository.

Dann, wenn es in der Dienstschicht ein Validierungsfehler ist, werfe ich eine benutzerdefinierte Ausnahme, es in der Steuerung fangen, und die Fehler in dem Modell Zustand injiziert.

Ich habe keine Antwort auf Ihre Frage, aber Sie können sharparchitecture.net Website überprüfen. Es enthält einige bewährte practives für asp.net Mvc und nhibernate. Ich kann Ihnen auch empfehlen xval Projekt und Anleitungen Validieren mit Data Annotation Validatoren

prüfen

Ich habe die Lösung gefunden, die für mich funktioniert, ist zu

1.) Fragen Sie, ob das Unternehmen gilt Ihre Validierungsarbeiten auszuführen.
2.) Danach abgeschlossen haben, etwas auf dem Objekt haben soll zu zeigen, es ist gültig ist oder nicht (in meinem Fall verwende ich ein CSLA wie Begriff der „broken-Regeln“).
3.) Wenn Sie so etwas wie dieses haben, können Sie überprüfen das Objekt gültig ist, bevor es NHibernate bestehen bleiben versucht, wie unten gezeigt.

Das einzige Problem mit diesem Ansatz ist, dass Sie eine Schnittstelle auf jeder Entität Validierung erfordern, implementieren müssen. Wenn Sie damit leben können, wird es NHibernate von persistierenden die Änderungen eines Objekts zu stoppen, die nach Ihren Regeln nicht gültig ist.

using System;
using NHibernate;
using NHibernate.Event;
using Validation.Entities.Interfaces;
using Persistence.SessionBuilder;

namespace Persistence.Validation
{
    public class ValidationEventListener : IPreInsertEventListener, IPreUpdateEventListener
    {

        public bool OnPreInsert(NHibernate.Event.PreInsertEvent @event)
        {
            var entityToInsert = @event.Entity as IBusinessBase;

            if (entityToInsert != null)
            {
                if (entityToInsert.BrokenRules != null)
                {
                    RollbackTransactionBecauseTheEntityHasBrokenRules();
                }
            }

            return false;
        }

        public bool OnPreUpdate(NHibernate.Event.PreUpdateEvent @event)
        {
            var entityToUpdate = @event.Entity as IBusinessBase;

            if (entityToUpdate != null)
            {
                if (entityToUpdate.BrokenRules != null)
                {
                    RollbackTransactionBecauseTheEntityHasBrokenRules();
                }
            }

            return false;
        }

        private void RollbackTransactionBecauseTheEntityHasBrokenRules()
        {
            try
            {
                ISession session = SessionBuilderFactory.GetBuilder().CurrentSession;

                if (session != null)
                {
                    session.Transaction.Rollback();
                }
            }
            catch (Exception ex)
            {
                //this will force a rollback if we don't have a session bound to the current context 
                throw new NotImplementedException();
            }
        }
    }
}

Ich würde sagen, dass dies auf Ihrer Architektur zählt. Mit MVC-Anwendungen, die ich in der Vergangenheit getan haben wir abstrakt die Domain Sachen weg von der Web-Zeug weg und natürlich verwenden wir Dependency Injection zu harten Abhängigkeiten zu vermeiden.

Wenn es um die Validierung des Modells kommt, wenn Sie in der Tat sind sie binden, ja Sie einfach den Service, Repository verwenden könnte, oder was auch immer Sie als nächstes in Ihrer Architektur in einem ValidateSelf Verfahren haben. Ich denke, dass sich die Frage, was über diese Abhängigkeit.

Wenn ich mich richtig erinnere, können Sie Ihre eigene kundenspezifische Mappe erstellen, die Ihre Dependency Injection-Framework Plug-in allen Diensten Ihr Modell benötigt für die Validierung verwenden, wenn Sie es schaffen, rufen Standardbinder MVC in dem Objekt zu füllen, dann rufen Sie in Castle Validierung des Rahmens für die Validierung zu tun. Dies ist keine voll dachte Lösung, aber hoffentlich provoziert es einige Ideen.

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