DbSet n’a pas de méthode Find dans EF7

J’essaie de créer un référentiel générique pour accéder à ma firebase database. En EF6, j’ai pu faire cela pour obtenir une entité spécifique:

protected IDbSet dbset; public T Get(object id) { return this.dbset.Find(id); } 

DbSet dans EF7 manque une méthode Find. Existe-t-il un moyen d’implémenter le code ci-dessus?

Voici une implémentation très grossière, incomplète et non testée de .Find() tant que méthode d’extension. Si rien d’autre, il devrait vous amener dans la bonne direction.

L’implémentation réelle est suivie par # 797 .

 static TEntity Find(this DbSet set, params object[] keyValues) where TEntity : class { var context = ((IAccessor)set).Service.GetService(); var entityType = context.Model.GetEntityType(typeof(TEntity)); var key = entityType.GetPrimaryKey(); var ensortinges = context.ChangeTracker.Ensortinges(); var i = 0; foreach (var property in key.Properties) { var keyValue = keyValues[i]; ensortinges = ensortinges.Where(e => e.Property(property.Name).CurrentValue == keyValue); i++; } var entry = ensortinges.FirstOrDefault(); if (entry != null) { // Return the local object if it exists. return entry.Entity; } // TODO: Build the real LINQ Expression // set.Where(x => x.Id == keyValues[0]); var parameter = Expression.Parameter(typeof(TEntity), "x"); var query = set.Where((Expression>) Expression.Lambda( Expression.Equal( Expression.Property(parameter, "Id"), Expression.Constant(keyValues[0])), parameter)); // Look in the database return query.FirstOrDefault(); } 

Si vous utilisez EF 7.0.0-rc1-final , vous trouverez ci-dessous une petite mise à jour du code présenté par @bricelam dans la réponse précédente. Au fait, merci beaucoup @bricelam – votre code m’a été extrêmement utile.

Voici mes dépendances sous “project.config”:

 "dependencies": { "EntityFramework.Commands": "7.0.0-rc1-final", "EntityFramework.MicrosoftSqlServer": "7.0.0-rc1-final", "Microsoft.Framework.Configuration.Json": "1.0.0-beta8", "Microsoft.Framework.ConfigurationModel": "1.0.0-beta4", "Microsoft.Framework.ConfigurationModel.Json": "1.0.0-beta4", "Microsoft.Framework.DependencyInjection": "1.0.0-beta8" } 

Et ci-dessous est la méthode d’extension pour DbSet.Find (TEntity) :

 using Microsoft.Data.Entity; using Microsoft.Data.Entity.Infrastructure; using System; using System.Linq; using System.Linq.Expressions; namespace Microsoft.Data.Entity.Extensions { public static class Extensions { public static TEntity Find(this DbSet set, params object[] keyValues) where TEntity : class { var context = ((IInfrastructure)set).GetService(); var entityType = context.Model.FindEntityType(typeof(TEntity)); var key = entityType.FindPrimaryKey(); var ensortinges = context.ChangeTracker.Ensortinges(); var i = 0; foreach (var property in key.Properties) { ensortinges = ensortinges.Where(e => e.Property(property.Name).CurrentValue == keyValues[i]); i++; } var entry = ensortinges.FirstOrDefault(); if (entry != null) { // Return the local object if it exists. return entry.Entity; } // TODO: Build the real LINQ Expression // set.Where(x => x.Id == keyValues[0]); var parameter = Expression.Parameter(typeof(TEntity), "x"); var query = set.Where((Expression>) Expression.Lambda( Expression.Equal( Expression.Property(parameter, "Id"), Expression.Constant(keyValues[0])), parameter)); // Look in the database return query.FirstOrDefault(); } } } 

Vous ne pouvez pas commenter à cause de votre réputation, mais si vous utilisez RC2 (ou plus tard?), Vous devez utiliser

 var context = set.GetService().Context; 

au lieu de

 var context = set.GetService(); 

J’ai pris certaines des réponses fournies précédemment et les ai modifiées pour résoudre quelques problèmes:

  • Fermeture implicitement capturée
  • La clé ne doit pas être codée en dur sur “Id”

     public static TEntity Find(this DbSet set, params object[] keyValues) where TEntity : class { var context = set.GetService(); var entityType = context.Model.FindEntityType(typeof(TEntity)); var key = entityType.FindPrimaryKey(); var ensortinges = context.ChangeTracker.Ensortinges(); var i = 0; foreach (var property in key.Properties) { var i1 = i; ensortinges = ensortinges.Where(e => e.Property(property.Name).CurrentValue == keyValues[i1]); i++; } var entry = ensortinges.FirstOrDefault(); if (entry != null) { // Return the local object if it exists. return entry.Entity; } var parameter = Expression.Parameter(typeof(TEntity), "x"); var query = set.AsQueryable(); i = 0; foreach (var property in key.Properties) { var i1 = i; query = query.Where((Expression>) Expression.Lambda( Expression.Equal( Expression.Property(parameter, property.Name), Expression.Constant(keyValues[i1])), parameter)); i++; } // Look in the database return query.FirstOrDefault(); } 

Donc … les méthodes de recherche ci-dessus ont bien fonctionné, mais si vous n’avez pas de colonne nommée “Id” dans votre modèle, tout va échouer sur la ligne suivante. Je ne suis pas sûr pourquoi l’OP aurait mis une valeur codée dans cet endroit

  Expression.Property(parameter, "Id"), 

Voici une révision qui le corrigera pour ceux qui nomment nos colonnes Id de manière appropriée. 🙂

 var keyCompare = key.Properties[0].Name; // TODO: Build the real LINQ Expression // set.Where(x => x.Id == keyValues[0]); var parameter = Expression.Parameter(typeof(TEntity), "x"); var query = set.Where((Expression>) Expression.Lambda( Expression.Equal( Expression.Property(parameter, keyCompare), //Expression.Property(parameter, "Id"), Expression.Constant(keyValues[0])), parameter)); // Look in the database return query.FirstOrDefault(); } 

Ce STILL très bien pourrait échouer si vous avez plus d’une installation de clé sur l’object entité et que la clé recherchée par vous n’est pas la première, mais elle devrait être un peu plus rapide.

Pas assez de réputation pour commenter, mais il y a un bogue dans la réponse de @Roger-Santana lorsque vous l’utilisez dans une application console / un assemblage séparé:

 var i = 0; foreach (var property in key.Properties) { ensortinges = ensortinges.Where(e => e.Property(property.Name).CurrentValue == keyValues[i]); i++; } var entry = ensortinges.FirstOrDefault(); 

La valeur de ‘i’ est capturée dans foreach, de sorte que lorsque ensortinges.FirstOrDefault () est appelée, keyValues ​​[i] a la valeur (au moins) keyValues ​​[i ++], qui dans mon cas est tombé en panne avec une erreur d’index . Une solution serait de copier la valeur de “i” dans la boucle:

 var i = 0; foreach (var property in key.Properties) { var idx =i; ensortinges = ensortinges.Where(e => e.Property(property.Name).CurrentValue == keyValues[idx]); i++; } var entry = ensortinges.FirstOrDefault(); 

Find finalement arrive dans le kernel d’Entity Framework.

J’utilise linq ; au lieu de la méthode Find , vous pouvez utiliser:

 var record = dbSet.SingleOrDefault(m => m.Id == id) 

Permettez-moi de consortingbuer à une révision qui inclut la construction de l’expression. J’avoue que je n’ai pas testé ça 😉

  public static TEntity Find(this DbSet dbSet, params object[] keyValues) where TEntity : class { // Find DbContext, entity type, and primary key. var context = ((IInfrastructure)dbSet).GetService(); var entityType = context.Model.FindEntityType(typeof(TEntity)); var key = entityType.FindPrimaryKey(); // Build the lambda expression for the query: (TEntity entity) => AND( entity.keyProperty[i] == keyValues[i]) var entityParameter = Expression.Parameter(typeof(TEntity), "entity"); Expression whereClause = Expression.Constant(true, typeof(bool)); uint i = 0; foreach (var keyProperty in key.Properties) { var keyMatch = Expression.Equal( Expression.Property(entityParameter, keyProperty.Name), Expression.Constant(keyValues[i++]) ); whereClause = Expression.And(whereClause, keyMatch); } var lambdaExpression = (Expression>)Expression.Lambda(whereClause, entityParameter); // Execute against the in-memory entities, which we get from ChangeTracker (but not filtering the state of the entities). var ensortinges = context.ChangeTracker.Ensortinges().Select((EntityEntry e) => (TEntity)e.Entity); TEntity entity = ensortinges.AsQueryable().Where(lambdaExpression).First(); // First is what sortingggers the query execution. // If found in memory then we're done. if (entity != null) { return entity; } // Otherwise execute the query against the database. return dbSet.Where(lambdaExpression).First(); } 

voici ce que j’utilise. Pas une méthode de recherche, mais fonctionne comme un charme

 var professionalf = from m in _context.Professionals select m; professionalf = professionalf.Where(s => s.ProfessionalId == id); Professional professional = professionalf.First(); 

Une modification a été proposée pour remplacer “.First ()” par “.FirstOrDefault ()” à la toute dernière ligne de mon article précédent. L’édition a été rejetée, mais je suis d’accord avec elle. Je m’attendrais à ce que la fonction renvoie null si la clé n’a pas été trouvée. Je ne voudrais pas qu’il lance une exception. Dans la plupart des cas, je voudrais savoir si la clé existe dans le jeu, et gérer une exception est un moyen très lent de le comprendre.