Comment généraliser l'accès à l'DbSet<TEntity> les membres d'une DbContext?
J'ai un DbContext
avec plusieurs types de membres:
public DbSet<JobLevel> JobLevels { get; set; }
public DbSet<Country> Countries { get; set; }
public DbSet<Race> Races { get; set; }
public DbSet<Language> Languages { get; set; }
public DbSet<Title> Titles { get; set; }
Tous ces sont where T: IdNamePairBase
, qui a Id
et Name
membres seulement. J'essaie désespérément de trouver une interface commune pour accéder à l'un de ces membres, de généraliser la suite de MVC3 contrôleur de code dans un contrôleur:
public ActionResult Edit(DropDownListModel model, Guid)
{
var dbSet = _dbContext.Countries;
var newItems = model.Items.Where(i => i.IsNew && !i.IsDeleted).Select(i => new { i.Name });
foreach (var item in newItems)
{
if (!string.IsNullOrWhiteSpace(item.Name))
{
var undead = ((IEnumerable<IdNamePairBase>)dbSet).FirstOrDefault(p => p.Name.ToLower() == item.Name.ToLower());
if (undead != null)
{
//Assign new value to update to the new char. case if present.
undead.Name = item.Name;
undead.IsDeleted = false;
_dbContext.SaveChanges();
continue;
}
var newPair = new Country { Name = item.Name };
dbSet.Add(newPair);
_dbContext.SaveChanges();
}
}
return RedirectToAction("Edit", new {listName = model.ListName});
}
Comment pourrais-je aller sur la résolution de mon problème que pour l'instant, j'ai besoin d'un contrôleur pour chaque DbContext
membres, comme celle ci-dessus est dédié à DbSet<Country> Countries
?
SOLUTION PARTIELLE: le Long des lignes semblables à GertArnold la réponse ci-dessous, avant que je savais à propos de la _dbContext.Set<T>
tout ce qu'il souligne, j'ai mis en œuvre cette méthode sur ma classe de contexte pour obtenir des ensembles d'un type spécifique:
public IEnumerable<DbSet<T>> GetDbSetsByType<T>() where T : class
{
//var flags = BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance;
var props = GetType().GetProperties()
.Where(p => p.PropertyType.IsGenericType && p.PropertyType.Name.StartsWith("DbSet"))
.Where(p => p.PropertyType.GetGenericArguments().All(t => t == typeof(T)));
return props.Select(p => (DbSet<T>)p.GetValue(this, null));
}
OriginalL'auteur ProfK | 2012-03-21
Vous devez vous connecter pour publier un commentaire.
La généralisation est possible en utilisant
et de mettre la plupart de votre méthode dans une méthode avec un des génériques du type de paramètre.
Cependant, il devrait y avoir un interrupteur quelque part à décider quel type doit être spécifié, et le type à créer, parce que je pense que le type est fourni comme une propriété du modèle (est-il?). Donc, il ne sera probablement pas vraiment look élégant, mais probablement beaucoup plus courtes, avec SÈCHE-er code.
OriginalL'auteur Gert Arnold
À ajouter sur Gert Arnold réponse, je tiens à souligner qu'il existe une autre méthode de surcharge sur le dbContext qui renvoie un général DbSet à partir d'un objet de type:
Si vous souhaitez ajouter à l'aveugle d'un objet, puis de créer l'objet en utilisant la
set.Create()
méthode, ou si vous avez déjà un objet créé avec la "new
" keyowrd, vous pouvez le convertir en utilisant (similaire à cette réponse)OriginalL'auteur yoel halb
J'ai été à la recherche d'une réponse à cette question et j'ai trouvé que c'est facile à faire en utilisant le Managed Extensibility Framework. Il y a un moyen plus rapide au bas de ce post, cependant MEF permet pour une approche évolutive.
MEF permet de construire des dynamiques d'accès plugins à partir de différents Assemblages; toutefois, il peut être utilisé pour remplir Collections au sein d'une assemblée unique de l'application.En essence, nous allons l'utiliser comme un moyen sûr de la réflexion de notre assemblée de retour dans la classe. Afin de faire de ce bien fonctionnel, je vais également mettre en œuvre la Stratégie de Modèle pour le Modèle d'Entity Framework.
Ajouter une référence à votre projet, pointant vers
System.ComponentModel.Composition
. Cela vous donnera accès à la MEF de la bibliothèque.Maintenant, nous avons besoin de mettre en œuvre le Modèle de Stratégie. Si vous n'avez pas un dossier Interfaces, créer une, et ajouter IEntity.cs, comme ci-dessous.
IEntity.cs
Maintenant, chacun de vous des entités concrètes doivent implémenter cette Interface:
Je trouve qu'il est de bonne pratique, de ne pas créer des interfaces individuelles pour chaque entité, sauf si vous travaillez dans une grande environnement de test. De façon pragmatique, l'interface doit être utilisé uniquement lorsque le niveau d'abstraction est nécessaire; surtout lorsque plus d'un béton de classe héritera, ou lorsque vous travaillez avec un enthousiaste Inversion de Contrôle moteur. Si vous avez des interfaces pour tout dans votre modèle de production, votre architecture plus que probablement, a de nombreux défauts. Bref, assez de la randonnée.
Maintenant que nous avons toutes nos entités "réfléchi et faire l'objet", nous pouvons utiliser la MEF pour les recueillir et de les peupler une collection au sein de votre contexte.
Au sein de votre contexte, ajoutez une nouvelle propriété:
La
[ImportMany(typeof(DbSet<IEntity>))]
ici, permet MEF pour remplir la collection.Ensuite, ajoutez le correspondant
Export
attribut à chaque DbSet dans le contexte:Chacun des
Import
ed etExport
ed propriétés est connu comme une "partie". La dernière pièce du puzzle est de composer les parties. Ajoutez les lignes suivantes à votre contexte constructeur:Maintenant, avec un peu de chance, vous devriez avoir un rempli dynamiquement la liste des DbSets, à l'intérieur de votre cadre.
J'ai utilisé cette méthode pour faciliter la troncature de toutes les tables via une méthode d'extension.
J'ai ajouté une méthode pour le contexte de tronquer l'ensemble de la base de données.
ÉDITION (Révision):
La solution ci-dessus a été amortis. Certains tweeking que devait être fait pour obtenir que cela fonctionne maintenant. Pour faire ce travail, vous devez importer le DbSets en une temporaire de la collection de DbSet de type "objet", puis lancer cette collection de DbSet de votre type d'interface. De base, le IEntity interface suffira.
Ensuite, exécutez le
CompileSetsList()
façade du constructeur (avec les meilleures pratiques pour le Web):Ensuite, il suffit de décorer votre DbSet<>s comme ceci:
Maintenant il ne fonctionne plus correctement.
OriginalL'auteur Apache