Disons que j'ai un DBContext avec 3 DBSets:
var _A = GetCode(TheDB.As, "123"); var _B = GetCode(TheDB.Bs, "123"); var _C = GetCode(TheDB.Cs, "123");
Je veux écrire une méthode générique qui:
DbSet comme premier argument IEnumerable , renvoie le premier enregistrement dans le DbSet fourni où le champ Code correspond à la chaîne fournie Jusqu'à présent, j'ai cette méthode:
public static T GetCode<T>(IQueryable<T> set, string code) where T : class
{
var Prop = typeof(T).GetProperty("Code");
return set.Where(x => (string)Prop.GetValue(x) == code).FirstOrDefault();
}
Quand j'essaye de l'appeler en utilisant cette ligne:
public class DatabaseContext : DbContext
{
public DbSet<A> As { get; set; }
public DbSet<B> Bs { get; set; }
public DbSet<C> Cs { get; set; }
}
class A
{
public string Text { get; set; }
public string Code { get; set; }
}
class B
{
public string Name { get; set; }
public string Code { get; set; }
}
class C
{
public string Book { get; set; }
public string Code { get; set; }
}
3 Réponses :
L'approche la plus simple (et sans risque de type) serait de simplement créer une interface comme IHaveCode et de lui limiter le paramètre générique:
interface IHaveCode
{
string Code { get; set; }
}
class A: IHaveCode
{
public string Text { get; set; }
public string Code { get; set; }
}
class B: IHaveCode
{
public string Name { get; set; }
public string Code { get; set; }
}
class C: IHaveCode
{
public string Book { get; set; }
public string Code { get; set; }
}
public static T GetCode<T>(IQueryable<T> set, string code) where T : IHaveCode
{
return set.Where(x => x.Code == code).FirstOrDefault();
}
Si pour une raison quelconque cela ne vous convient pas alors vous devrez construire un arbre d'expression vous-même.
Une méthode plus générique que celle de Guru Stron, qui est également utilisable pour les DbSets de classes sans propriété Code , serait de fournir la propriété que vous souhaitez utiliser dans votre comparaison.
// Get a C by Book title: string bookTitle = ... C fetchedC = dbContext.Cs.GetFirstPropertyOrDefault(c => c.Book);
Usage:
string comparisonValue = ... A fetchedA = dbContext.As.GetFirstPropertyMachOrDefault(a => a.Code, comparisonValue);
Mais maintenant que vous l'avez rendu générique, vous pouvez également l'utiliser pour récupérer d'autres propriétés; p >
public static T GetFirstPropertyMatchOrDefault<T>(
this IQueryable<T> source,
Expression<Func<T, string>> propertySelector,
string comparisonValue)
{
return source.Where(sourceElement => propertySelector(sourceElement) == comparisonValue)
.FirstOrDefault();
}
Vous pouvez implémenter la méthode GetCode en utilisant Arbres d'expression .
public static T GetCode<T>(IQueryable<T> set, string code) where T : class {
PropertyInfo codeProp = typeof(T).GetProperty("Code");
if(codeProp == null)
throw new ArgumentException($"{typeof(T).FullName} does not have the Code property");
ParameterExpression param = Expression.Parameter(typeof(T));
Expression getCode = Expression.MakeMemberAccess(param, codeProp);
Expression codeVal = Expression.Constant(code);
Expression body = Expression.Equal(getCode, codeVal);
Expression<Func<T, bool>> predicate = Expression.Lambda<Func<T, bool>>(body, param);
return set.FirstOrDefault(predicate);
}