10
votes

Si la couche d'interface utilisateur est-elle capable de passer des expressions Lambda dans la couche de service au lieu d'appeler une méthode spécifique?

Le projet ASP.NET que je travaille sur 3 couches; UI, BLL et DAL. Je voulais savoir s'il était acceptable pour l'interface utilisateur de passer une expression de Lambda à la BLL, ou si l'interface utilisateur doit passer des paramètres et que la méthode de service doit utiliser ces paramètres pour construire l'expression Lambda? Voici un exemple de classe montrant à la fois SENARIOS.

JobService jobService = new JobService(new Repository<Job>());
Job job = jobService.Get(x => x.JobID == 1).FirstOrDefault();


0 commentaires

6 Réponses :


8
votes

Ceci est un appel de jugement basé sur la situation. Ce n'est pas nécessairement faux de transmettre un prédicat comme celui-ci. Je pense que cela devrait être considéré comme une une mauvaise odeur mineure cependant.

Si le passage d'une expression de Lambda vous permet de réduire 6 méthodes jusqu'à 1, cela pourrait être un bon coup. D'autre part, si vous pouvez simplement passer facilement dans un type simple, la syntaxe Lambda est une complication inutile.

Dans l'exemple ci-dessus, ne connaissant pas le contexte, ma préférence serait d'utiliser un paramètre de nombres entiers simples. Il devrait généralement s'agir d'une méthode de base qui obtient juste un enregistrement par son identifiant. Et peut-être une ou deux autres méthodes de ce type qui sont utilisées à plusieurs reprises via votre application. Et ensuite peut-être une méthode générale qui prend une Lambda.

Vous devez également déterminer ce que certains suggéreraient devraient être une règle: que vous ne possède aucune méthode avec des prédicats spécifiés par Lambda entre votre UI et votre couche d'entreprise . (Et certains croient, avec raison, que vos référentiels ne devraient même pas avoir de telles méthodes!) Je ne crois pas que cela devrait être une règle de fer clavier, mais il y a de bonnes raisons à cela. Vos couches d'affaires et de données, entre eux, devraient conserver des requêtes dangereuses de se produire. Si vous autorisez le passage de Lambdas, il est très facile pour un développeur junior dans la couche d'interface utilisateur de spécifier des requêtes qui pourraient vraiment tuyer votre base de données. (Par exemple, ils feront des requêtes énormes contre des champs non indexés et / ou un filtre contre les résultatsset à l'aide de Linq-to-objets, et ne réalisez pas à quel point cela est inefficace.)

Comme beaucoup d'autres bonnes pratiques, cela dépendra un peu sur la portée . Dans ma récente grande application, j'ai NO Passage de la syntaxe de Lambda à partir de la couche d'interface utilisateur à la couche d'entreprise. Mon plan était d'investir lourdement dans la couche d'entreprise, de le rendre très intelligent. Il a toutes les méthodes nécessaires avec des types simples. En fait, cela vous donne généralement ce dont vous avez besoin à travers des propriétés d'objet de domaine simples, sans paramètres du tout. Mon interface garantit que l'interface utilisateur ne peut que provoquer des requêtes efficaces ne se produisent peut-être que des prédicats mineurs linq-to-objets dans la couche d'interface utilisateur. (Cela va même pour les pages "Rechercher". Ma couche d'entreprise accepte un objet de critères avec des possibilités contraintes et assure une requête efficace.)

Maintenant, vous avez dit "couches", plutôt que "niveaux". Donc, ce sont tous dans la même assemblée? Un autre inconvénient de Lambda est (actuellement) difficile à sérialiser. Donc, vous les regretteriez si vous deviez séparer vos niveaux.


0 commentaires

1
votes

Je ne ferais pas ça. C'est une mauvaise pratique. C'est légal, mais mauvais.

Vous ajoutez une logique DAL à l'interface utilisateur rendant votre dal comme une enveloppe. Votre interface utilisateur ne doit transmettre que les paramètres sur le BLL ou DAL, et non exécuter la logique pour obtenir les données.


0 commentaires

1
votes

Ceci est juste mon avis, mais ce que vous essayez d'écrire des regards similaires à la façon dont une expression LINQ est écrite, donc si elle est assez bonne pour Linq, alors pourquoi pas vous?

Si vous pensez que cela facilite votre travail, je ne vois pas pourquoi vous ne devriez pas le faire. La seule chose que je me méfierais, c'est sûr qu'il est facile de maintenir, c'est-à-dire que possible de garder une trace de tous ces lambdas que vous passez.


0 commentaires

2
votes

En supposant que la raison pour laquelle vous pensez que cela ne soit peut-être pas approprié, c'est que cela pourrait violer l'encapsulation du BLL, je vais aller avec cela dépend .

délégués et Lambda Expressions sont des constructions de langue de base afin que le simple acte de les utiliser ne soit pas t rompre toute encapsulation en soi.

L'exception est bien sûr si la signature du délégué est transmise comme argument sur une méthode expose un type qui ne doit pas être consulté directement de la portée de l'appelant . Laissez-moi vous donner un exemple: xxx

Dans le premier exemple, la signature de la méthode enfreint l'encapsulation en exposant un détail de mise en œuvre à l'appelant sous la forme du SQLCOMMAND type. Il accorde également l'appelant trop de liberté en lui permettant de spécifier une requête comme argument, qui est dangereux dangereux.

dans le deuxième exemple, d'autre part, la signature de la méthode Simple expose une classe de modèle, qui fait déjà partie de l'interface publique de la couche. Cela n'augmente pas la superficie de l'API et n'expose aucun détail sur la manière dont l'opération est mise en œuvre.


0 commentaires

4
votes

Ceci est toujours un point de théâtre sur lequel la "couche" qui expose les arbres d'expression (et iquéryable s) devrait être limitée à.

Tout d'abord, l'évidence - le principal avantage de permettre un iquéryable lambda dans une couche permet évidemment une flexibilité énorme dans la requête, sans avoir besoin d'écrire beaucoup de getxxxbyyyy Méthodes de type. Les couches de clients peuvent également contrôler directement les jointures en utilisant .include pour spécifier la profondeur de la récupération de graphique et peuvent contrôler la commande ( .orderby ), regroupement ( .groupby ), Limites de ligne ( .take ) dans la base de données, qui aura généralement des gains de performance sur la même chose en mémoire.

Les inconvénients incluent:

  • Testability - car l'interface est tellement ouverte, il existe un grand nombre de permutations arbitrairement à vérifier.
  • Trust - Les clients de votre couche ont un règne libre pour exécuter des requêtes arbitraires contre votre base de données, ce qui pourrait avoir des problèmes de performance (c.-à-d. Les clients pourraient exécuter des requêtes qui manquent tous les index) et des problèmes de sécurité (récupération des données auxquelles ils ne devraient pas avoir accès ).
  • Série de sérialisation - Les arbres d'expression ne peuvent pas être directement sérialisés, vous ne pouviez donc pas exposer votre BLL à travers E.G. Wcf (bien qu'ils puissent être proxés)

    Si vous autorisez l'arborescence d'expression en tant que paramètre, je vous suggérerais d'aller «tout le chemin» et de retourner Iquérisable au lieu d'iEnumerable. Cela permettra aux requêtes d'être chaîgées / agrégées (par exemple, vous pouvez modifier la requête plus tard, avant de le matérialiser)

    Personnellement, nous n'autorisons personnellement que les arbres d'expression dépassent notre BLL, nous ne l'étendrions donc pas à notre UI - imo expression <> Les prédicats sont perçus comme mécanisme de mise en œuvre d'Evan's Href = " https://stackoverflow.com/questions/1436663/specification-pattern-example">Specification motif.


0 commentaires

2
votes

Je n'aime personnellement pas ça. Je suppose que ce n'est pas faux, mais cela crée une zone grise de l'endroit où vous devriez écrire vos requêtes. Je pense que lorsque quelqu'un d'autre entre dans ma demande et que toutes les expressions sont dans une belle couche, cela facilite la navigation.


0 commentaires