Question

Cette question ne me laisse pas dormir car il est depuis un an, je suis en train de trouver une solution, mais ... toujours rien ne se passait dans mon esprit. Probablement, vous pouvez me aider, parce que je pense que cela est un problème très commun.

J'ai une application n-couches: la couche de présentation, couche logique métier, couche de modèle. Supposons pour simplifier que mon application contient, dans la couche de présentation, une forme qui permet à un utilisateur de rechercher un client. Maintenant, l'utilisateur remplit les filtres via l'interface utilisateur et clique sur un bouton. Quelque chose se passe et que la demande arrive à la couche de présentation à une méthode comme CustomerSearch(CustomerFilter myFilter). Cette couche logique métier maintient maintenant simple: crée une requête sur le modèle et obtient en retour des résultats.

Maintenant la question: comment faites-vous face au problème des données de chargement? Je veux dire couche logique métier ne sait pas que cette méthode particulière sera invoquée que par cette forme. Donc, je pense qu'il ne sait pas si le formulaire de demande doit juste les objets Client dos ou les objets clients avec les entités de commande liées.

J'essaie d'expliquer mieux: notre formulaire veut juste liste Les clients effectuant une recherche par nom de famille. Cela n'a rien à voir avec les commandes. Ainsi, la requête de la logique métier sera quelque chose comme:

(from c in ctx.CustomerSet
where c.Name.Contains(strQry) select c).ToList();

cela fonctionne correctement. Deux jours plus tard, votre patron vous demande d'ajouter un formulaire qui vous permettent de rechercher des clients comme l'autre et vous devez indiquer le nombre total de commandes créées par chaque client. Maintenant, je voudrais réutiliser cette requête et ajoutez le morceau de logique qui attache ( comprend ) commandes et récupère que.

Comment voulez-vous avant cette demande?

Voici le meilleur (je pense) idée que j'avais depuis maintenant. Je voudrais vous entendre: ma méthode de CustomerSearch dans BLL ne crée pas la requête directement, mais passe par des méthodes d'extension privées qui composent ObjectQuery comme:

private ObjectQuery<Customer> SearchCustomers(this ObjectQuery<Customer> qry, CustomerFilter myFilter)

et

private ObjectQuery<Customer> IncludeOrders(this ObjectQuery<Customer> qry)

mais cela ne me convainc pas car il semble trop complexe.

Merci, Marco

Était-ce utile?

La solution

envisager de passer à de DTO pour l'interface entre la couche de présentation et la couche métier, voir par exemple: - http://msdn.microsoft.com/en-us/magazine/ee236638.aspx

Quelque chose comme Automapper peut soulager une grande partie de la douleur associée à passer à DTO et le mouvement va expliciter ce que vous pouvez et ne pouvez pas faire avec les résultats d'une requête, à savoir si elle est sur le DTO il est chargé, si ce n'est pas vous avez besoin un autre DTO.

Votre plan actuel semble un peu trop couplé étroitement entre la couche de présentation et la couche de données.

Autres conseils

Je suis d'accord avec le commentaire de Hightechrider en référence à l'utilisation de DTO, mais vous avez une question valable en ce qui concerne les entités commerciales.

Une solution possible (j'utilise quelque chose le long de ces lignes sur un projet que je développe) est d'utiliser DTO qui sont en lecture seule (au moins du point de vue de la couche de présentation. Votre requête / get opérations ne reviendrait DTO , cela vous donne la capacité de chargement paresseux.

Vous pourriez configurer votre couche d'affaires pour retourner un objet éditable qui enveloppe le DTO lorsqu'un objet / entité est mis à jour / créé. Votre objet modifiable pourrait appliquer des règles métier, puis quand il a été sauvé / passé à la couche d'affaires DTO enveloppé (avec les valeurs mises à jour) pourraient être transmises à la couche de données.

public class Editable
{
    //.......initialize this, other properties/methods....

    public bool CanEdit<TRet>(Expression<Func<Dto, TRet>> property)
    {
        //do something to determine can edit
        return true;
    }

    public bool Update<TRet>(Expression<Func<Dto, TRet>> property, TRet updatedValue)
    {
        if (CanEdit(property))
        {
            //set the value on the property of the DTO (somehow)
            return true;
        }
        return false;
    }

    public Dto ValueOf { get; private set;}
}

Cela vous donne la possibilité d'appliquer si l'utilisateur peut obtenir des objets modifiables de la couche d'affaires ainsi que de permettre l'objet métier de faire respecter si l'utilisateur est autorisé à modifier les propriétés spécifiques d'un objet. Un problème commun je rencontre avec le domaine que je travaille dans est que certains utilisateurs peuvent modifier toutes les propriétés et autres ne peuvent pas, alors que tout le monde peut voir les valeurs des propriétés. De plus, la couche de présentation gagne la capacité de déterminer ce qu'il faut exposer éditable à l'utilisateur comme dicté et appliqué par la couche d'affaires.

Autre pensée que je HAD ne peut pas votre couche d'affaires ou exposer IQueryable prendre des expressions standards comme arguments que vous passez à votre couche de données. Par exemple, j'ai un bâtiment page requête quelque chose comme ceci:

public class PageData
{
    public int PageNum;
    public int TotalNumberPages;
    public IEnumerable<Dto> DataSet;
}

public class BL
{
    public PageData GetPagedData(int pageNum, int itemsPerPage, Expression<Func<Dto, bool>> whereClause)
    {
        var dataCt = dataContext.Dtos.Where(whereClause).Count();
        var dataSet = dataContext.Dtos.Where(whereClause).Skip(pageNum * itemsPerPage).Take(itemsPerPage);

        var ret = new PageData
                        { 
                          //init this
                        };

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