J'ai donc créé une couche d'accès aux données via TDD et j'ai abordé une certaine préoccupation. Je préfère ne pas m'engager dans la mauvaise voie, alors j'ai pensé que je vous demanderais de voir si mes pensées étaient conformes à une architecture propre.
Les méthodes de ma couche d'accès aux données (DAL pour faire court) sont assez simples. Ils sont en ligne avec les procédures stockées dans la base de données (aucun autre moyen de l'appeler pour garder les choses propres), et ils contiennent les mêmes paramètres que les procédures. Ils se connectent ensuite à la base de données et renvoient le résultat de la requête. Voici un exemple:
public int DeleteRecord(int recordId)
{
recordId.RequireThat("recordId").NotZeroOrLess();
List<SqlParameter> parameters = new List<SqlParameter>();
parameters.Add(new SqlParameter { ParameterName = "@RecordId", SqlDbType = SqlDbType.Int, Direction = ParameterDirection.Input, Value = recordId});
return this.ExecuteNonQuery("DeleteRecord", parameters.ToArray());
}
Cela fonctionne parfaitement pour ce type de méthode, car je ne fais rien de significatif avec l'ensemble de résultats. Je veux juste m'assurer que la commande a fonctionné, donc je vais retourner le résultat de la non-requête, qui est juste les lignes affectées, et je peux vérifier la logique en utilisant ce numéro.
Cependant, disons dans une autre méthode DAL, je veux charger un enregistrement. Ma procédure de chargement va être exécutée selects
sur un tas de tables et renvoyer un DataSet
, mais je me demande si mon DAL doit créer les objets métier dans la méthode en utilisant le DataSet
, ou si mes objets métier eux-mêmes devraient simplement avoir une Load()
méthode qui obtient le DataSet
du DAL, puis se remplit essentiellement.
Le faire via le DAL entraînerait moins de logique dans les objets métier (même s'il ne s'agit que d'une logique sélectionnée, c'est toujours de la logique), mais surchargerait un peu le DAL et donnerait l'impression qu'il fait vraiment quelque chose qu'il ne devrait pas '' t faire.
Qu'en pensez-vous?
Réponses:
Votre DAL doit renvoyer vos objets de données
Idéalement, votre DAL devrait être un objet "boîte noire", que votre code d'application peut utiliser pour demander un objet de données ou manipuler des objets de données existants. Parfois, il existe une autre couche placée entre le DAL et le code d'application appelé le
Repository
, qui sépare davantage les deux couches, bien que ce ne soit pas toujours nécessaire.En outre, vous ne souhaitez généralement pas que vos objets métier puissent se créer eux-mêmes. Cela peut provoquer des failles de sécurité où quelqu'un peut utiliser votre bibliothèque et créer une nouvelle instance de votre objet en l'appelant
.Load(someId)
, et cela fusionne deux couches qui devraient être complètement séparées.Je ne recommande pas non plus de fournir une
.Load(DataSet ds)
méthode, car si la définition de l'ensemble de données change, vous devrez rechercher les objets de données qui utilisent cet ensemble de données et les modifier. Il est plus facile de conserver tous vos codes d'accès aux données en un seul endroit, donc si vous modifiez la requête d'accès aux données, vous ne devriez avoir qu'à changer votre couche DAL.la source
BusinessObject bo = DAL.LoadRecord(id);
- sound right? La logique pour mapper la requête au BO lui-même serait contenue dans le DAL, et seulement là.Get
au lieu deLoad
, commeCustomer c = DAL.GetCustomer(id);
Ma méthode, même avant LINQ-To-SQL et Entity Framework, consistait à avoir une interface et une bibliothèque de classes abstraites qui fournissaient un "contrat écrit" pour la communication entre les différentes couches de l'application. Ceci est parfois appelé une ontologie , une définition d'un domaine de travail. Tout ce qui passait entre les couches utilisait ce «contrat».
Je n'aime pas l'idée de passer des objets de jeu de données bruts de la couche de données à la couche métier. J'ai vu ce résultat dans un certain nombre de problèmes, en particulier lors de l'intégration de sources de données héritées. Il peut également être très difficile pour les nouvelles personnes entrant dans un projet de comprendre d'où proviennent les données. Enfin, cela nécessite que votre couche métier soit chargée de gérer les données directement à partir de la base de données, ce qui peut entraîner des complications en cours de route.
L'exemple de code que vous aviez ressemble au code que j'avais avant LINQ. J'avais une classe de fonction DB commune que j'utilisais dans mes objets DAL. Les classes DAL liraient les données et les adapteraient aux objets «contrat». Les résultats scalaires, comme votre exemple de suppression, renverraient une valeur, généralement un booléen.
la source
ExecuteScalar
renvoient le résultat direct des requêtes pour renvoyer des valeurs qui ont plus de sens pour une couche de gestion, commebool
? Je pense que sinon, c'est une réponse très similaire à celle de Rachel.Votre DAL doit renvoyer un ensemble de données. Cet ensemble de données renvoyé doit être l'objet commercial, il ne doit y avoir rien d'autre à faire que de vérifier qu'il contient les données attendues. Si vous devez en faire plus, vous essayez d'en faire trop dans une seule procédure stockée ou de ne pas renvoyer correctement les données dans la procédure stockée.
la source
Je recommanderais à vos objets métier d'avoir un constructeur pour se remplir à partir d'un ensemble de résultats. Cela supprime le couplage entre votre DAL et la couche métier. Si vous souhaitez isoler complètement les deux, créez une mappe simple de paires nom de colonne => valeur à partir de votre jeu de résultats et passez-la au constructeur.
la source