web-dev-qa-db-fra.com

Utilisation du référentiel générique et des procédures stockées

Je travaille sur une application existante qui utilise d'abord le modèle de dépôt générique et la base de données EF 6. J'appelle un processus stocké qui renvoie un type complexe qui n'est pas une entité existante dans mes modèles d'entité et par conséquent, je ne suis pas sûr. quel type donner 

Voici comment mon sp est appelé depuis ma couche service

_unitOfWork.Repository<Model>()
            .SqlQuery("sp_Get @FromDateTime, @ToDateTime, @CountyId",
                         new SqlParameter("FromDateTime", SqlDbType.DateTime) { Value = Request.FromDateTime },
                         new SqlParameter("ToDateTime", SqlDbType.DateTime) { Value = Request.TripToDateTime },
                         new SqlParameter("CountyId", SqlDbType.Int) { Value = Convert.ToInt32(Request.County) }
           ).ToList();

Est-ce que je crée une entité dans ma couche de données à mapper ou quelle est la meilleure approche pour les procédures stockées renvoyant des types complexes? Si oui, un mappage personnalisé est-il nécessaire ou s'agit-il simplement de créer la classe Entity?

je vous remercie

9
user2329438

Si vous avez une entité avec ces champs, vous pouvez appeler la méthode SqlQuery comme indiqué ci-dessus. Sinon, je suggère de créer une nouvelle classe pour mapper le résultat:

public class Result
{
    public int CountyId { get; set; }

    public DateTime FromDateTime { get; set; }

    public DateTime ToDateTime { get; set; }
}

Je ne sais pas comment le modèle UnitOfWork est implémenté dans votre cas, mais je suppose que vous avez accès à votre contexte. Dans votre classe UnitOfWork, vous pouvez créer une méthode générique comme celle-ci:

public class UnitOfWork 
{
    private YourContext Context { get; set; }

    public DbRawSqlQuery<T> SQLQuery<T>(string sql, params object[] parameters)
    {
       return Context.Database.SqlQuery<T>(sql, parameters);
    }
}

De cette façon, vous pouvez exécuter vos procédures de magasin comme je le montre ci-dessous:

var result= _unitOfWork.SqlQuery<Result>("sp_Get @FromDateTime, @ToDateTime, @CountyId",
                     new SqlParameter("FromDateTime", SqlDbType.DateTime) { Value = Request.FromDateTime },
                     new SqlParameter("ToDateTime", SqlDbType.DateTime) { Value = Request.TripToDateTime },
                     new SqlParameter("CountyId", SqlDbType.Int) { Value = Convert.ToInt32(Request.County) }
       ).ToList();
14
octavioccl

Le but de Repository Pattern est d’abriter le stockage et la récupération des données afin de protéger votre code client, par exemple. la couche de gestion (la couche de service dans votre cas) n’a plus besoin de savoir comment les données sont conservées. Les instructions SQL, par exemple, n'existeraient que dans vos classes Repository et ne se répercuteraient pas dans votre code.

Si vous exposez le code client, les noms de procédure stockée et les paramètres à votre code client, vous n'obtenez pas beaucoup d'avantages avec le modèle de référentiel, et vous ne pouvez vraiment pas l'appeler du tout un référentiel. Vous perdez l'avantage de pouvoir simuler le référentiel et de tester votre couche métier indépendamment de votre couche d'accès aux données. Cela signifie que des tests d'intégration (nécessitant une instance de base de données complète) sont nécessaires pour vérifier la logique métier.

Envisagez de procéder à une nouvelle factorisation afin d'avoir une classe CountryRepository qui possède une méthode GetCountry (int CountryId, DateTime fromDate, DateTime toDate) qui renvoie une entité Country ou similaire. Je pense que vous conviendrez que la lisibilité de votre code sera bien améliorée par rapport au code de votre question.

public class CountryRepository
{
  public Country GetCountry(int CountryId, DateTime fromDate, DateTime toDate)
  {
    // EF or ADO.NET code here
  }
}

Le code client serait alors par exemple.

var c = unitOfWork.CountryRepository.GetCountry(1, DateTime.Now.AddYears(-1), DateTime.Now);

Voir aussi ceci SO question

9
saille

ma façon

    IQueryable<Cm_Customer> customerQuery = _uow.SqlQuery<Cm_Customer>(@" DECLARE @UserId INT = {0}
                                               EXEC Cm_GetCustomersByUserId @UserId", filter.UserId).AsQueryable();
    IQueryable<Cm_Customer> custs = customerQuery.IncludeMultiple(k => k.Cm_CustomerLocations,
                                           k => k.Cm_CustomerSalesmans,
                                           k => k.Cm_CustomerMachineparks,
                                           k => k.Cm_CustomerAuthenticators,
                                           k => k.Cm_CustomerInterviews,
                                           k => k.Cm_CustomerRequest,
                                           k => k.Cm_MachineparkRental).AsQueryable();

La manière ci-dessus ne fonctionne pas dans mon cas et j'écris ci-dessus et cela a fonctionné pour moi pour n'importe qui dans mon cas

0
dewelloper