Question

J'ai un très gros problème et je n'arrive pas à trouver quelqu'un d'autre sur Internet qui a mon problème. J'espère bien que StackOverflow pourra m'aider ...

J'écris une application ASP.NET MVC et j'utilise le concept de référentiel avec Linq To Sql comme magasin de données. Tout fonctionne très bien en ce qui concerne la sélection des lignes à partir des vues. Et piéger les contraintes de base des règles métier. Cependant, je suis confronté à un problème dans mes mappages de procédures stockées pour les suppressions, les insertions et les mises à jour. Laissez-moi vous expliquer:

Notre administrateur de base de données a déployé beaucoup d'efforts pour intégrer la logique métier à toutes nos procédures stockées afin que je n'ai pas à m'en soucier. Bien sûr, je fais la validation de base, mais il gère l’intégrité des données et les contraintes de date conflictuelles, etc. Le problème auquel je suis confronté est que toutes les procédures stockées (et je veux dire toutes) ont 5 paramètres supplémentaires (6 pour les insertions). ) qui me fournissent des informations. L'idée est que lorsque quelque chose se brise, je peux demander à l'utilisateur les informations appropriées de notre base de données.

Par exemple:

sp_AddCategory(
    @userID INT,
    @categoryName NVARCHAR(100),
    @isActive BIT,
    @errNumber INT OUTPUT,
    @errMessage NVARCHAR(1000) OUTPUT,
    @errDetailLogID INT OUTPUT,
    @sqlErrNumber INT OUTPUT,
    @sqlErrMessage NVARCHAR(1000) OUTPUT,
    @newRowID INT OUTPUT)

Dans la procédure stockée ci-dessus, les 3 premiers paramètres sont les seuls paramètres utilisés pour "Créer". l'enregistrement de la catégorie. Les paramètres restants sont simplement utilisés pour me dire ce qui s'est passé dans la méthode. Si une règle de gestion est rompue dans la procédure stockée, il n'utilise PAS le mot clé SQL 'RAISEERROR' lorsque les règles de gestion sont rompues. Au lieu de cela, il me fournit des informations sur l'erreur à l'aide des paramètres OUTPUT. Il le fait pour chaque procédure stockée dans notre base de données, même les mises à jour et les suppressions. Tous les appels "Get" sont effectués à l'aide de vues personnalisées. Ils ont tous été testés et l’idée était de faciliter mon travail car je n’étais pas obligé d’ajouter la logique métier pour piéger tous les scénarios afin d’assurer la qualité des données.

Comme je l'ai dit, j'utilise Linq To Sql et je suis maintenant confronté à un problème. Le problème est que mon " catégorie " L'objet de modèle a simplement 4 propriétés: CategoryID, CategoryName, UserId et IsActive. Lorsque j'ai ouvert le concepteur pour commencer à mapper mes propriétés pour l'insertion, je me suis rendu compte qu'il n'y avait vraiment aucun moyen (facile) de prendre en compte les paramètres supplémentaires, à moins que je ne les ajoute à mon objet Model.

Théoriquement, ce que j'aimerais faire est la suivante:

// note: Repository Methods
public void AddCategory(Category category)
{
    _dbContext.Categories.InsertOnSubmit(category);
}

public void Save()
{
    _dbContext.SubmitChanges();
}

Ensuite, dans ma classe CategoryController, je ferais simplement ce qui suit:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
{
    var category = new Category();
    try 
    {
        UpdateModel(category); // simple validation here...

        _repository.AddCategory(category);
        _repository.Save(); // should get error here!!

        return RedirectToAction("Index");
    }
    catch
    {
        // manage friendly messages here somehow... (??)
        // ...

        return View(category);
    }
}

Quel est le meilleur moyen de gérer cela en utilisant Linq to Sql? Personnellement, je ne pense pas qu'il soit logique d'ajouter toutes ces propriétés supplémentaires à chaque objet du modèle ... Par exemple, "Get" ne devrait JAMAIS avoir d'erreurs et je ne veux pas que mes méthodes de référentiel en renvoient une type d'objet pour les appels Get, mais accepte un autre type d'objet pour les appels CUD.

Mise à jour: ma solution! (1er décembre 2009)

Voici ce que j'ai fait pour résoudre mon problème. Je me suis débarrassé de ma méthode 'Save ()' sur tous mes référentiels. Au lieu de cela, j'ai ajouté une méthode 'Update ()' à chaque référentiel et réellement validé les données dans la base de données à chaque appel CUD (c'est-à-dire créer / mettre à jour / supprimer).

Je savais que chaque procédure stockée avait les mêmes paramètres. J'ai donc créé une classe pour les contenir:

public class MySprocArgs 
{
    private readonly string _methodName;
    public int? Number;
    public string Message;
    public int? ErrorLogId;
    public int? SqlErrorNumber;
    public string SqlErrorMessage;
    public int? NewRowId;

    public MySprocArgs(string methodName)
    {
        if (string.IsNullOrEmpty(methodName))
            throw new ArgumentNullException("methodName");

        _methodName = methodName;
    }

    public string MethodName
    {
        get { return _methodName; }
    }

}

J'ai également créé une exception MySprocException qui accepte les MySprocArgs dans son constructeur:

public class MySprocException : ApplicationException
{

    private readonly MySprocArgs _args;
    public MySprocException(MySprocArgs args) : base(args.Message)
    {
       _args = args;
    }

    public int? ErrorNumber
    {
        get { return _args.Number; }
    }

    public string ErrorMessage
    {
        get { return _args.Message; }
    }

    public int? ErrorLogId
    {
        get { return _args.ErrorLogId; }
    }

    public int? SqlErrorNumber
    {
        get { return _args.SqlErrorNumber; }
    }

    public string SqlErrorMessage
    {
        get { return _args.SqlErrorMessage; }
    }
}

Maintenant, voici où tout se met en place ... À l'aide de l'exemple que j'ai cité lors de ma première enquête, voici à quoi pourrait ressembler la méthode 'AddCategory ()':

public void AddCategory(Category category)
{
   var args = new MySprocArgs("AddCategory");
   var result = _dbContext.AddWidgetSproc(
                    category.CreatedByUserId,
                    category.Name,
                    category.IsActive,
                    ref args.Number, // <-- Notice use of 'args'
                    ref args.Message,
                    ref args.ErrorLogId,
                    ref args.SqlErrorNumber,
                    ref args.SqlErrorMessage,
                    ref args.NewRowId);

   if (result == -1)
      throw new MySprocException(args);
} 

Maintenant, depuis mon contrôleur, je fais simplement ce qui suit:

[HandleError(ExceptionType = typeof(MySprocException), View = "SprocError")]
public class MyController : Controller
{
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(Category category)
    {
        if (!ModelState.IsValid)
        { 
            // manage friendly messages        
            return View(category);
        }

        _repository.AddCategory(category);
        return RedirectToAction("Index");

    } 
}

Pour gérer le nouveau MySprocException , il suffit de le capturer à l’aide de l’attribut HandleError et de le rediriger vers une page qui comprend l’exception MySprocException.

J'espère que cela aide quelqu'un. :)

Était-ce utile?

La solution

Je ne pense pas que vous puissiez ajouter les paramètres de sortie à l'une de vos classes LINQ car ces paramètres ne persistent dans aucune table de votre base de données.

Mais vous pouvez gérer les paramètres de sortie dans LINQ de la manière suivante.

Ajoutez la ou les procédures stockées que vous souhaitez appeler à votre fichier .dbml à l'aide du concepteur.

Appelez votre procédure stockée dans votre code

 using (YourDataContext context = new YourDataContext())
 {
    Nullable<int> errNumber = null;
    String errMessage = null;
    Nullable<int> errDetailLogID = null;
    Nullable<int> sqlErrNumber = null;
    String sqlErrMessage = null;
    Nullable<int> newRowID = null;
    Nullable<int> userID = 23;
    Nullable<bool> isActive=true;

    context.YourAddStoredProcedure(userID, "New Category", isActive, ref errNumber, ref errMessage, ref errDetailLogID, ref sqlErrNumber, ref sqlErrMessage, ref newRowID);
 }

Autres conseils

Je ne l'ai pas encore essayé, mais vous pouvez consulter cet article où il parle de procédures stockées qui renvoient des paramètres de sortie.

http://weblogs.asp.net/scottgu/archive/2007/08/16/linq-to-sql-part-6-retrieving-data-using-stored-procedures.aspx

Glissez la procédure stockée dans votre concepteur LINQ to SQL, puis faites le travail à votre place.

Le dbContext.SubmitChanges (); fonctionnera uniquement avec ENTITY FRAMEWORK.Je suggère Enregistrer, mettre à jour et supprimer fonctionnera à l'aide d'une procédure stockée unique ou de trois procédures différentes.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top