Erstellen generischer Linq-Abfragen

.net c# database expression-trees linq

Frage

Ich habe eine Datenbank mit zwei Tabellen:

public class A {
    public string Name { get; set; }
    public int Id { get; set; }
}

public class B {
    public int Id { get; set; }
    public bool Prop1 { get; set; }
    public bool Prop2 { get; set; }
    public bool Prop3 { get; set; }
    public bool Prop4 { get; set; }
}

public class DataContext : DbContext {
    DbSet<A> Table1 { get; set: }
    DbSet<B> Table2 { get; set; }
}

Ich möchte eine Funktion schreiben, die als Parameter "Prop1", "Prop2", ..., "PropX" verwendet und entsprechende Zeilen aus Table1 zurückgibt. Etwas wie das:

public List<A> GetByProp(string prop) {
    var result = new List<A>();

    using (var db = new DataContext()) {
        result = db.Table1.Join(db.Table2, t1=>t1.Id, t2=>t2.Id, (t1,t2)=>new {t1,t2}).
                           Where(????????). //t=>t.t2.prop == true
                           Select(t=>t.t2);

    }
    return result;
}

Was ist ein geeigneter Weg, dies zu tun?

Ich habe versucht, Expression Tree zu verwenden, aber ich habe ihre ...

  1. Wie erstelle ich einen Ausdruck mit zwei Punkten? (t.t2.prop == wahr)

  2. Wie kann ich den anonymen Typ (den Join () generiert) an generische übergeben?

    var p = Expression.Parameter(typeof(???), t2); //??? - anonymous class
    var t = Expression.Constant(true, typeof(bool));
    var e = Expression.Equal(p, t);
    var l = Expression.Lambda<Func<???, bool>>(e, p);
    

Akzeptierte Antwort

Wie wäre es mit der Platzierung der Bedingung als Teil der Join Methodenquelle?

Bei diesem Ansatz benötigt Ihre Bedingung den Expression<Func<B, true>> und Sie können einen Expression<Func<B, true>> einfach mit Expression Tree Expression<Func<B, true>> .

List<T> result;

var param = Expression.Parameter(typeof(B), "x");
var trueExp = Expression.Constant(true);
var condition = Expression.Equal(Expression.Property(param, prop), trueExp);
var whereLambda = Expression.Lambda<Func<B, bool>>(condition, param);

using (var db = new DataContext())
{
    result = db.Table1
               .Join(db.Table2.Where(whereLambda),
                     t1 => t1.Id,
                     t2 => t2.Id,
                     (t1, t2) => new { t1, t2 })
               .Select(t => t.t1)
               .ToList();
}
return result;

Aktualisieren

Wenn Sie Ihrem ursprünglichen Entwurf folgen möchten, sollten Sie den Compiler auf Ihren anonymen Typ schließen lassen:

public static Expression<Func<T, bool>> GetPropertyCondition<T>(T source, string prop)
{
    var param = Expression.Parameter(typeof(T), "x");
    var trueExp = Expression.Constant(true);
    var condition = Expression.Equal(
                        Expression.Property(
                            Expression.Property(param, "t2"), prop),
                            trueExp);
    var whereLambda = Expression.Lambda<Func<T, bool>>(condition, param);
    return whereLambda;
}

und du kannst es so nennen:

var result = new List<A>();

var anonymous = new { t1 = (A)null, t2 = (B)null };
var condition = GetPropertyCondition(anonymous, prop);

using (var db = new DataContext())
{
    result = db.Table1.AsQueryable()
               .Join(db.Table2.AsQueryable(), t1 => t1.Id, t2 => t2.Id, (t1, t2) => new { t1, t2 })
               .Where(condition)
               .Select(t => t.t1)
               .ToList();
}
return result;

Es verwendet die Tatsache, dass jedes Objekt anonymen Typs mit der gleichen Gruppe von Eigenschaften (sowohl Eigenschaftenname und Eigenschaftstyp übereinstimmen müssen) innerhalb der Assembly die gleiche zugrunde liegende anonyme Klasse teilen. Daher stimmt typeof(anonymous) hier mit dem Typ überein, der von der Join Erweiterungsmethode zurückgegeben wird.



Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow