2 Stimmen

LINQ-to-SQL "Member access not legal on type"-Ausnahme mit vereinigter und kompilierter Abfrage

Ich habe mehrere Abfragen, die ich zusammenführen und dann das Ganze kompilieren möchte. Die nicht kompilierte Abfrage läuft gut, aber eine "InvalidOperationException: Member access 'Int32 Id' of 'UserQuery+Foo' not legal on type 'System.Linq.IQueryable`1[UserQuery+Foo]." wird ausgelöst, wenn die gleiche Abfrage kompiliert und ausgeführt wird.

Wie kann ich das beheben?

void Main()
{
    var db = new MyDataContext( "..." );

    Expression < Func < DataContext, int, IQueryable < Foo > > > queryExpression = (DataContext dc, int unused) =>
        from ab in GetA(dc).Union( GetB(dc) )
        group ab by new { ab.Id, ab.Name } into grp
        select new Foo
        {
            Id = grp.Key.Id,
            Name = grp.Key.Name,
            Total = grp.Count()
        };

    var final = CompiledQuery.Compile ( queryExpression );

    var result1 = queryExpression.Compile () (db, 0);  // calling the original query works fine
    var result2 = final (db, 0);            // calling the compiled query throws an exception
}

public class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Total { get; set; }
}

IQueryable<Foo> GetA( DataContext db )
{
    return from b in db.GetTable<Bar>()
    where b.IsActive
    select new Foo { Id = b.Id, Name = b.Name };
}

IQueryable<Foo> GetB( DataContext db )
{
    return from b in db.GetTable<Bar>()
    where !b.IsActive
    select new Foo { Id = b.Id, Name = b.Name };
}

EDIT

Es sieht so aus, als ob die Vereinigung und Gruppierung irrelevant sind. Das Entfernen dieser Elemente aus der Abfrage führt beim Kompilieren immer noch zu einer Ausnahme:

    Expression < Func < DataContext, int, IQueryable < Foo > > > queryExpression = (DataContext dc, int unused) =>
        from a in GetA(dc)
        select new Foo
        {
            Id = a.Id,
            Name = a.Name,
            Total = 42
        };

Ersetzen des Aufrufs an GetA(dc) avec dc.GetTable<Bar>() und das Hinzufügen der Where-Klausel behebt das Problem.

Ist es also bei kompilierten Abfragen einfach nicht möglich, getrennte Abfragen auf diese Weise miteinander zu verbinden?

EDIT #2

James' Antwort traf den Nagel auf den Kopf. Wenn man die Anfrage noch weiter vereinfacht, wird das eigentliche Problem deutlich:

    Expression < Func < DataContext, int, IQueryable < Foo > > > queryExpression = (DataContext dc, int unused) =>
        from a in GetA(dc)
        select a;

Diese Abfrage wirft NotSupportedException: Method 'System.Linq.IQueryable``1[UserQuery+Foo] GetA(System.Data.Linq.DataContext)' has no supported translation to SQL.

Das Ausgliedern des Aufrufs von GetA in eine separate Variablenzuweisung und die anschließende Verwendung dieser Variablen in der Abfrage führt zu einem InvalidOperationException: Sequence contains more than one element Ausnahme.

1voto

jpierson Punkte 14912

Ich hatte das gleiche Problem, und was schien, den Trick für mich zu tun war eine Inline statische Methode aufrufen, die IQueryable<> zurückgegeben, so dass ich diese verzögerte Abfrage in eine Variable gespeichert und referenziert, dass.

Ich denke, dass dies ein Fehler in Linq to SQL ist, aber zumindest gibt es eine vernünftige Abhilfe.

0voto

James Curran Punkte 98228

Meine Vermutung ist, dass der Linq-Compiler die Methoden, die IQueryable zurückgeben, nicht versteht.

Um es zu kompilieren, müssten diese Methoden wahrscheinlich eine Form von Expression<> zurückgeben.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X