Warum funktioniert diese LINQ-Join-Anweisung nicht?

c# entity-framework join linq linq-to-entities

Frage

Ich habe diese LINQ-Abfrage:

    // types...
    LinkedList<WeightedItem> itemScores = new LinkedList<WeightedItem>();

    var result = from i in _ctx.Items
                 join s in itemScores on i.Id equals s._id
                 orderby s._score descending
                 select new ItemSearchResult(i, s._score);

    // this fails:
    return result.ToList();

Welche erzeugt diesen Fehler:

Konstanter Wert des Typs 'System.Collections.Generic.IEnumerable`1' kann nicht erstellt werden.
In diesem Zusammenhang werden nur primitive Typen (z. B. Int32, String und Guid) unterstützt.

[EDIT] Hier ist der Code von WeightedItem :

public class WeightedItem
{
    public int _id;
    public decimal? _score;

    public WeightedItem(int id, decimal? score)
    {
        _id = id;
        _score = score;
    }
}

Kannst du sehen, was ich falsch gemacht habe? Der Code wird perfekt kompiliert und sowohl _ctx.Items als auch itemScores enthalten korrekte Werte.

Akzeptierte Antwort

Ja, es würde gut kompilieren - das Problem ist, dass es nicht in SQL übersetzt werden kann. Wenn Sie auf "lokale" Werte verweisen, muss das Entitätsframework herausfinden, was mit diesen zu tun ist, wenn eine SQL-Abfrage erstellt werden muss. Im Grunde kann es keine Verknüpfung zwischen einer In-Memory-Collection und einer Datenbanktabelle schaffen.

Eine Sache, die funktionieren könnte , wäre stattdessen die Verwendung von Contains . Ich weiß nicht, ob LinkedList<T> dafür funktionieren wird, aber ich glaube, dass List<T> zumindest in LINQ to SQL funktioniert:

List<int> requiredScoreIds = itemScores.Select(x => x._id).ToList();

var tmp = (from i in _ctx.Items
           where requiredScoreIds.Contains(i.Id)
           orderby s._score descending
           select i).AsEnumerable();

// Now do the join in memory to get the score
var result = from i in tmp
             join s in itemScores on i.Id equals s._id
             select new ItemSearchResult(i, s._score);

Das macht jetzt einen Join in der In-Memory-Abfrage, was etwas unnötig ist. Sie können stattdessen ein Wörterbuch verwenden:

List<int> requiredScoreIds = itemScores.Select(x => x._id).ToList();

var tmp = (from i in _ctx.Items
           where requiredScoreIds.Contains(i.Id)
           orderby s._score descending
           select i).AsEnumerable();

// Create a map from score ID to actual score
Dictionary<int, decimal?> map = itemScores.ToDictionary(x => x._id,
                                                        x => x._score);

var result = tmp.Select(i => new ItemSearchResult(i, map[i.Id]));

Beliebte Antwort

Sie können keine Verknüpfung zwischen einer In-Memory-Liste und einem abfragbaren Objekt herstellen. Sie müssen so etwas tun:

var criteria = itemScores.Select(x => x._id).ToList();
var result_tag = (from i in _ctx.Items
                 where criteria.Contains(i.ID)
                 select i).ToList();
var result = from i in result_tag
             join s in itemScores on i.ID equals s._id
             orderby s._score descending
             select new ItemSearchResult(i, s._score);


Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum