Sélectionnez top1 avec Linq

En fait, je travaille avec Linq et UOW (unité de travail), et je fais tout l'access facile à bbdd avec linq. Je sais que si je veux get la première rangée d'une table, je peux faire ceci:

int test4 = (from p in uow.ProductR.context.product where p.Id == 1715 select p.Id).FirstOrDefault(); 

Cela va exécuter ceci dans SQL Server:

 SELECT TOP (1) [Extent1].[Id] AS [Id] FROM [dbo].[product] AS [Extent1] WHERE 1715 = [Extent1].[Id] 

Mes questions sont, puis-je faire la même chose avec LINQ pour objecter avec les repositorys generics de mon UOW? Je veux dire, quand j'exécute

 int test2 = uow.ProductR.Get(p => p.Id == 1715).Select(p => p.Id).FirstOrDefault(); 

Ou

 var test3 = uow.ProductR.Get(p => p.Id == 1715).Select(p => new { p.Id }); 

Dans SQL Server, j'obtiens:

 SELECT [Extent1].[Id] AS [Id], [Extent1].[Name] AS [Name], FROM [dbo].[product] AS [Extent1] WHERE 1715 = [Extent1].[Id] 

Bien sûr, avec la deuxième méthode, lorsque la database contient 500k lignes, elle sera lente. (J'ai plus de colonnes, non seulement 2)

Edité: Voici la class avec les déclarations GET

 public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class { internal contextEntities context; internal DbSet<TEntity> dbSet; public GenericRepository(contextEntities context) { this.context = context; this.dbSet = context.Set<TEntity>(); } public virtual IEnumerable<TEntity> Get( Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, ssortingng includeProperties = "") { IQueryable<TEntity> query = this.dbSet; if (filter != null) { query = query.Where(filter); } foreach (var includeProperty in includeProperties.Split(new char[] { ',' }, SsortingngSplitOptions.RemoveEmptyEnsortinges)) { query = query.Include(includeProperty); } if (orderBy != null) { return orderBy(query).AsQueryable(); } else { return query.AsQueryable(); } } } 

J'espère que j'ai bien expliqué.

Get doit renvoyer un IQueryable , pas un IEnumerable comme il le fait maintenant. Ensuite, l'argument de Get devient également inutile car l'appelant peut simplement faire Get().Where(...) . La surface de l'API devient plus propre car vous pouvez supprimer l'argument.

Mais vous perdez le contrôle de la façon dont la database est interrogée. Je suppose que vous faites un repository à des fins de test (sinon c'est probablement un mauvais choix d'en avoir un). Tester les requêtes qui sont exécutées de cette façon devient plus difficile.

Renvoyer un IQueryable vous donnera une plus grande flexibilité, mais il expose également la possibilité de modification occasionnelle des requêtes que vous avez définies dans votre repository. Si vous souhaitez fournir un mécanisme standard à quelqu'un qui utilise votre référentiel pour renvoyer les N lignes supérieures, vous pouvez append des propriétés facultatives supplémentaires (notez que Take, en conjonction avec Skip, est un mécanisme utile si vous souhaitez également autoriser la pagination via votre référentiel sans créer de mécanisme séparé ou exposer l'IQueryable sous-jacent).

Vous pouvez changer la signature de votre méthode Get à quelque chose comme ceci:

 public virtual IEnumerable<TEntity> Get( Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, ssortingng includeProperties = "", int? maxResults = null) 

Ensuite, dans votre méthode Get (ceci devrait être refactorisé, mais vous avez l'idée):

  if (orderBy != null) { return maxResults.HasValue() ? orderBy(query).Take((int)maxResults).ToList() : orderBy(query).ToList(); } else { return maxResults.HasValue() ? query.take((int)maxResults).ToList() : query.ToList(); } 

Notez que votre appel à AsQueryable () ne devrait pas être nécessaire puisque IOrderedQueryable et IQueryable implémentent IEnumerable. Au lieu de cela, appelez ToList () afin de matérialiser le jeu de résultats afin qu'il s'exécute.