3

J'ai une base de données mis en correspondance avec Entity Framework,Entity Framework dynamique DbSet pour toutes les entités

Je dois mettre en œuvre une méthode générique pour obtenir aa liste des éléments en fonction d'un paramètre que je passe:

getGenericList("product"); // returns the list of products 
getGenericList("customer"); // returns the list of customers 

Je dois dynamiquement obtenir le dbSet. Ma méthode est mise en œuvre comme ceci:

public static List<object> getGenericList(string entityType) 
    { 
     List<object> myDynamicList = new List<object>(); 
     using (cduContext db = new cduContext()) 
     { 
      DbSet dbSet = db.getDBSet(entityType); 
      var myDynamicList = dbSet.Select(p => p).ToList(); 
     } 
     return new List<object>(); 
    } 

mon dbSets sont le code généré automatiquement par EF première:

public DbSet<Product> Products { get; set; } 
public DbSet<Custommer> Custommers { get; set; } 

ma méthode getDBSet(entityType) est mis en œuvre dans le contexte, comme celui-ci:

public DbSet<T> getDBSet<T>(string entityName) where T : class 
    { 
     switch (entityName) 
     { 

      case "product": 
       return Products; 

      case "custommer": 
       return Custommers; 

J'ai ensuite eu cette erreur:

Cannot implicitly convert type 'System.Data.Entity.DbSet' to 'System.Data.Entity.DbSet'

Une idée s'il vous plaît!?

N.B. , la méthode Set() du dbContext n'est pas OK; le type doit être donné explicitement ...

+0

Vous pouvez corriger l'orthographe de « custommer » -> « client » dans votre code actuel. – MEMark

Répondre

2

Il est préférable de rester à l'écart des chaînes comme types et les mapper à des types réels; c'est une odeur de code. Au lieu de cela, utilisez les types eux-mêmes. Quoi qu'il en soit, refactorisons votre code qui utilise la méthode getGenericList() pour utiliser des génériques. Si vous ne pouvez pas échapper aux chaînes, faites le mappage dans le code qui appelle getGenericList() par opposition au mappage à l'intérieur de cette méthode, car nous suivons le modèle que vous avez défini.

Notez également que dans votre getGenericList() d'origine, vous renvoyez toujours une liste vide, contrairement à la liste que vous avez obtenue via EF. Vous utilisez également 2 variables myDynamicList différentes; l'externe est masqué par celui dans la portée de l'instruction using, ce qui explique pourquoi vous n'obtenez pas d'erreur de compilation. Une fois que le using est hors de portée, le myDynamicList sort également du champ d'application. Je l'ai abordé ici.

public static List<T> getGenericList<T>() 
{ 
    List<T> myDynamicList; 

    using (cduContext db = new cduContext()) 
    { 
     // consider using exception handling here as GetDbSet might get an invalid type 
     DbSet dbSet = db.GetDbSet<T>(); 
     myDynamicList = dbSet.Select(p => p).ToList(); 
    } 

    if (myDynamicList != null && myDynamicList.Count() > 0) 
    { 
     return myDynamicList; 
    } 
    return new List<T>(); 
} 

// in your context class 
public DbSet<T> GetDbSet<T>() where T : class 
{ 
    return this.Set<T>(); 
} 

// this is the code that calls getGenericList(); put this inside a function somewhere. 
// entityName holds a string value, set previously 
switch(entityName.ToLower()) // making entityName case insensitive 
{ 
    case "product": 
     return getGenericList<Product>(); 

    case "customer": 
     return getGenericList<Customer>(); 
} 

Espérons que vous n'aurez pas trop de types d'entités que vous souhaitez mapper, ou vous finirez avec une énorme déclaration switch. Encore une fois, si vous utilisez une instruction switch, en général c'est probablement une indication que vous devez repenser votre approche.

0

Pour éviter le switch, vous pouvez rechercher le type par son nom qualifié d'assembly, puis obtenir le DbSet à partir de cela. Le DbSet récupéré de cette manière n'est pas générique <>, donc les opérations que vous pouvez effectuer sont plus limitées.

Vous pouvez obtenir le nom qualifié d'assembly en utilisant un type d'entité connue (par exemple Product), obtenir son nom de montage qualifié, puis remplacer « Produit » avec le nom de votre choix pour obtenir le type.

Cet exemple est simplifié à partir d'une application Breeze, dans laquelle certaines entités de recherche peuvent être demandées par le nom du client.

public async Task<List<object>> GetGenericList(string entityType) 
{ 
    using (var context = new MyContext()) 
    { 
    var aqtemp = typeof(Product).AssemblyQualifiedName; // template for qualified name 

    var aqname = aqtemp.Replace("Product", entityType); // qualified name for entityType 

    var type = Type.GetType(aqname, true, true);  // Type for entityType 

    var list = await context.Set(type).ToListAsync(); // query the entities 
    return list; 
    } 
} 
Questions connexes