Frage

Ist es möglich, Teile einer Linq-Abfrage in eine Funktion zu übergeben? Ich möchte eine gemeinsame Schnittstelle für meine DAL erstellen, die die gleiche Abfrage-Schnittstelle verwendet immer. Zum Beispiel:

List<T> Get(Join j, Where w, Select s){    
    return currentDataContext<T>.Join(j).Where(w).Select(s).ToList();    
}

Ist diese Art der Sache möglich? Ich denke, es wäre mit Ausdruck Bäumen getan werden, aber ich habe nicht in der Lage gewesen, Beispiele dafür zu finden.

War es hilfreich?

Lösung

Nun, die „Join“ ist schwierig, weil es sehr schwierig ist, eine Verknüpfung zum Ausdruck bringen - aber Dinge wie, wo / select / orderby sind recht einfach ...

Wirklich, es ist nur ein Fall von den verschiedenen LINQ Methoden auf IQueryable<T> Kombination, die in der Regel Expression<Func<...>> für eine Kombination akzeptieren. So ein Grund mit einem optionalen Prädikat wählen würde:

    public IQueryable<T> Get<T>(
        Expression<Func<T,bool>> predicate
        ) where T : class
    {
        IQueryable<T> query = (IQueryable<T>)GetTable(typeof(T));
        if (predicate != null) query = query.Where(predicate);
        return query;
    }

Ich würde dazu neigen, IQueryable<T> auch zurückkehren, da diese vollständig zusammensetzbare ist. Wenn der Anrufer eine Liste will, kann sie immer ToList() auf sich verwendet ... oder (zum Beispiel):

    using(var ctx = new MyDataContext(CONN))
    {
        ctx.Log = Console.Out;
        int frCount = ctx.Get<Customer>(c => c.Country == "France").Count();
    }

, die (mit Nordwind) funktioniert die Abfrage:

SELECT COUNT(*) AS [value]
FROM [dbo].[Customers] AS [t0]
WHERE [t0].[Country] = @p0

Das Problem mit, einschließlich der „select“ (Projektion) in der Abfrage ist, dass Sie mit mehreren generischen Typen enden würden. Da Sie oft den Vorsprung wollen würde das sein eine anonyme Art, es dann ziemlich unmöglich sein, den Projektionstyp (anonym) und , um den Tabellentyp angeben, und es wäre nicht aufrufbar sein.

In Wirklichkeit, frage ich mich, ob es viel Nutzen überhaupt, ein solches Verfahren zu schreiben. Ich könnte nur mit einer Basismethode halten:

    public IQueryable<T> Get<T>() where T : class
    {
        return (IQueryable<T>)GetTable(typeof(T));
    }

Und lassen Sie den Anrufer sie in ihrer bevorzugten Art und Weise komponiert - vielleicht mit Abfragesyntax:

       var list = (from cust in ctx.Get<Customer>()
                   where cust.Country == "France"
                   select cust.CompanyName).Take(10).ToList();

Welche verwendet:

SELECT TOP (10) [t0].[CompanyName]
FROM [dbo].[Customers] AS [t0]
WHERE [t0].[Country] = @p0

Alternativ, wenn Sie wirklich den Auftrag durch und Projektion zu verstehen wollen, dann ist eine Erweiterung Methode der praktischste Ansatz; dann brauchen Sie nicht das Original (Quelle) T angeben (das ist, was es unkündbare macht, wenn sie mit anon-Typen gemischt):

public static class QueryExtension
{
    public static IQueryable<TProjection>
        Get<TSource, TProjection, TOrderKey>(
            this IQueryable<TSource> source,
            Expression<Func<TSource, bool>> where, // optional
            Expression<Func<TSource, TProjection>> select,
            Expression<Func<TProjection, TOrderKey>> orderBy)
    {
        if (where != null) source = source.Where(where);
        return source.Select(select).OrderBy(orderBy);
    }
}

Dann wird eine DAL-Methode in Betracht ziehen:

    public List<string> Countries()
    {
        return Customers.Get(
            x=>x.CompanyName != "",
            x=>x.Country,
            x=>x).Distinct().ToList();
    }

Welche verwendet (wieder mit Nordwind):

SELECT DISTINCT [t0].[Country]
FROM [dbo].[Customers] AS [t0]
WHERE [t0].[CompanyName] <> @p0

Andere Tipps

Sie könnten a href verwenden <= "http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library aspx“rel = "nofollow noreferrer"> Dynamische LINQ und die Parameter in als Strings übergeben.

Marc GRA ♦, wie üblich, bot eine sehr interessante Antwort, aber ich glaube wirklich, mit Methoden, die nehmen IQueryables und fügen Sie Einschränkungen in den meisten Fällen funktionieren würde und sie halten den Code übersichtlicher und leicht wartbar. Zum Beispiel:

//Join
public static IQueryable<IContract> AllContracts(this IQueryable<IAccount> accounts, ISession s ) {
          return from a in accounts
                 from contract in s.Query<IContract()
                 where (a.Id == contract.AccountId)
                 select contract;
    }
//Where
public static IQueryable<IContract> Active(this IQueryable<IContract> contracts) {
          return from contract in contracts
                 where (contract.Active == true)
                 select contract;
    }

Dann können Sie diese wie folgt mischen und:

IQueryable<IContract> activeContracts = s.Query<IAccount>()
            .Where(o => o.Name == "XXX")
            .GetContracts(s)
            .Active();

Ich bin mit Erweiterungsmethoden und NHiberante LINQ Abfrage Methode bietet hier, aber dies leicht ohne statische Methoden und mit jeder LINQ-Provider neu geschrieben werden konnte.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top