209 Stimmen

Ergebnisse vom anonymen Typ zurückgeben?

Was ist die beste Methode, um mit Linq to SQL Ergebnisse aus mehreren Tabellen zurückzugeben, und zwar anhand des folgenden einfachen Beispiels?

Angenommen, ich habe zwei Tabellen:

Dogs:   Name, Age, BreedId
Breeds: BreedId, BreedName

Ich möchte alle Hunde mit ihren BreedName . Ich sollte alle Hunde mit so etwas ohne Probleme bekommen:

public IQueryable<Dog> GetDogs()
{
    var db = new DogDataContext(ConnectString);
    var result = from d in db.Dogs
                 join b in db.Breeds on d.BreedId equals b.BreedId
                 select d;
    return result;
}

Aber wenn ich Hunde mit Rassen will und das versuche, habe ich Probleme:

public IQueryable<Dog> GetDogsWithBreedNames()
{
    var db = new DogDataContext(ConnectString);
    var result = from d in db.Dogs
                 join b in db.Breeds on d.BreedId equals b.BreedId
                 select new
                        {
                            Name = d.Name,
                            BreedName = b.BreedName
                        };
    return result;
}

Jetzt erkenne ich, dass der Compiler nicht lassen Sie mich einen Satz von anonymen Typen zurückgeben, da es Dogs erwartet, aber gibt es eine Möglichkeit, dies zurückzugeben, ohne einen benutzerdefinierten Typ zu erstellen? Oder muss ich meine eigene Klasse für DogsWithBreedNames und geben Sie diesen Typ in der Select? Oder gibt es einen anderen, einfacheren Weg?

0 Stimmen

Nur so aus Neugier, warum zeigen alle Linq-Beispiele mit anonymen Typen, wenn sie nicht funktionieren. Z.B., dieses Beispiel tut foreach (var cust in query) Console.WriteLine("id = {0}, City = {1}", cust.CustomerID, cust.City);

0 Stimmen

@Hot Licks - die Tabelle Customer in diesen Beispielen ist eine Entität, die durch eine Klasse dargestellt wird. Das Beispiel scheint nur nicht die Definitionen dieser Klassen zu zeigen.

0 Stimmen

Sie erfahren auch nicht, dass ein Compilerfehler "var" durch den Klassennamen ersetzt.

2voto

George Mamaladze Punkte 7293

Sie können anonyme Typen nicht direkt zurückgeben, aber Sie können sie in einer Schleife durch Ihre generische Methode laufen lassen. Das gilt auch für die meisten LINQ-Erweiterungsmethoden. Da steckt keine Magie drin, auch wenn es so aussieht, als würden sie anonyme Typen zurückgeben. Wenn der Parameter anonym ist, kann das Ergebnis auch anonym sein.

var result = Repeat(new { Name = "Foo Bar", Age = 100 }, 10);

private static IEnumerable<TResult> Repeat<TResult>(TResult element, int count)
{
    for(int i=0; i<count; i++)
    {
        yield return element;
    }
}

Nachfolgend ein Beispiel, das auf dem Code der ursprünglichen Frage basiert:

var result = GetDogsWithBreedNames((Name, BreedName) => new {Name, BreedName });

public static IQueryable<TResult> GetDogsWithBreedNames<TResult>(Func<object, object, TResult> creator)
{
    var db = new DogDataContext(ConnectString);
    var result = from d in db.Dogs
                    join b in db.Breeds on d.BreedId equals b.BreedId
                    select creator(d.Name, b.BreedName);
    return result;
}

2voto

Yargicx Punkte 1552

Versuchen Sie dies, um dynamische Daten zu erhalten. Sie können Code für List<> konvertieren

public object GetDogsWithBreedNames()
{
    var db = new DogDataContext(ConnectString);
    var result = from d in db.Dogs
                 join b in db.Breeds on d.BreedId equals b.BreedId
                 select new
                        {
                            Name = d.Name,
                            BreedName = b.BreedName
                        };
    return result.FirstOrDefault();
}

dynamic dogInfo=GetDogsWithBreedNames();
var name = dogInfo.GetType().GetProperty("Name").GetValue(dogInfo, null);
var breedName = dogInfo.GetType().GetProperty("BreedName").GetValue(dogInfo, null);

0voto

Dave Markle Punkte 91733

Nun, wenn du Dogs zurückbringst, würdest du das tun:

public IQueryable<Dog> GetDogsWithBreedNames()
{
    var db = new DogDataContext(ConnectString);
    return from d in db.Dogs
           join b in db.Breeds on d.BreedId equals b.BreedId
           select d;
}

Wenn Sie möchten, dass die Rasse eager-loaded und nicht lazy-loaded ist, verwenden Sie einfach die entsprechende DataLoadOptions konstruieren.

0voto

Zhaph - Ben Duguid Punkte 26343

Wenn Sie in Ihrer Datenbank eine Beziehung mit einem Fremdschlüssel für BreedId eingerichtet haben, erhalten Sie dann nicht bereits diese Information?

DBML relationship mapping

Ich kann also jetzt anrufen:

internal Album GetAlbum(int albumId)
{
    return Albums.SingleOrDefault(a => a.AlbumID == albumId);
}

Und in dem Code, der das aufruft:

var album = GetAlbum(1);

foreach (Photo photo in album.Photos)
{
    [...]
}

In Ihrem Fall würden Sie also etwas wie dog.Breed.BreedName aufrufen - wie gesagt, dies hängt davon ab, dass Ihre Datenbank mit diesen Beziehungen eingerichtet ist.

Wie andere bereits erwähnt haben, helfen die DataLoadOptions, die Datenbankaufrufe zu reduzieren, wenn das ein Problem ist.

0voto

kad81 Punkte 10372

BreedId im Dog Tabelle ist offensichtlich ein Fremdschlüssel zu der entsprechenden Zeile in der Breed Tisch. Wenn Sie Ihre Datenbank richtig eingerichtet haben, sollte LINQ to SQL automatisch eine Verknüpfung zwischen den beiden Tabellen erstellen. Die daraus resultierende Klasse Dog hat eine Eigenschaft Breed, und die Klasse Breed sollte eine Sammlung Dogs haben. Wenn Sie es so einrichten, können Sie immer noch Folgendes zurückgeben IEnumerable<Dog> das ein Objekt ist, das die Eigenschaft "Rasse" enthält. Die einzige Einschränkung ist, dass Sie das Rasse-Objekt zusammen mit Hundeobjekten in der Abfrage vorladen müssen, damit auf sie zugegriffen werden kann, nachdem der Datenkontext entsorgt wurde, und (wie ein anderer Poster vorgeschlagen hat) eine Methode auf der Sammlung ausführen, die bewirkt, dass die Abfrage sofort ausgeführt wird (ToArray in diesem Fall):

public IEnumerable<Dog> GetDogs()
{
    using (var db = new DogDataContext(ConnectString))
    {
        db.LoadOptions.LoadWith<Dog>(i => i.Breed);
        return db.Dogs.ToArray();
    }

}

Es ist dann trivial, die Rasse für jeden Hund abzurufen:

foreach (var dog in GetDogs())
{
    Console.WriteLine("Dog's Name: {0}", dog.Name);
    Console.WriteLine("Dog's Breed: {0}", dog.Breed.Name);        
}

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