• Ich versuche das, aber ich kann FirstOrDefault nicht verwenden.

     public static int GetId(this Context db, Type type, string name)
    {
        return db.Set(type).FirstOrDefault(x => x.Name == name).Id;
    }
     

    Der Fehler ist ' System.Data.Entity.DbSet' enthält keine Definition für 'FirstOrDefault' und keine Erweiterungsmethode 'FirstOrDefault', die ein erstes Argument vom Typ 'System.Data' akzeptiert. Entity.DbSet 'konnte gefunden werden (fehlt eine using-Direktive oder eine Assemblyreferenz?)

    Ich habe dann diese Cast -Methode ausprobiert das zu einem Fehler geführt hat Es kann kein DbSet aus einem nicht generischen DbSet für Objekte vom Typ 'WindowStyle' erstellt werden. p>

     var set = db.Set(type).Cast<DomainEntity>();
    return set.FirstOrDefault(x => x.Name == name).Id;
     

    Hier ist die Klasse,

     public class DomainEntity
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
    }
     
    22 November 2011
    Benjamin
6 answers
  • Möglicherweise fehlt Ihnen

     using System.Linq;
     
    28 April 2013
    riseres
  • Diese Antwort hilft Ihnen möglicherweise nicht, abhängig davon, wie "dynamisch" die Situation ist, in der Sie diese Methode aufrufen. Grundsätzlich, wenn Sie den Typ zur Kompilierzeit kennen oder nicht. Wenn Sie es wissen, können Sie stattdessen eine generische Methode schreiben:

     public static class MyExtensions
    {
        public static int? GetId<TEntity>(this Context db, string name)
            where TEntity : DomainEntity
        {
            return db.Set<TEntity>()
                .Where(x => x.Name == name)
                .Select(x => (int?)x.Id)
                .FirstOrDefault();
        }
    }
     

    Ich habe es deshalb in eine Projektion geändert Sie müssen nicht die gesamte Entität laden, wenn Sie nur die ID wünschen. Sie können die Datenbank die Arbeit erledigen lassen, um die Eigenschaft auszuwählen, um die Leistung etwas zu verbessern. Ich gebe auch ein nullable int zurück, falls der Name in der Datenbank nicht übereinstimmt.

    Sie können dies in Ihrem Code wie folgt aufrufen:

     int? id = db.GetId<WindowStyle>("abc");
     

    Wie Sie für diese Lösung sehen können, müssen Sie den Typ WindowStyle zur Kompilierzeit angeben.

    Dies setzt voraus, dass DomainEntity nicht Teil Ihres Modells ist (es gibt kein DbSet<DomainEntity>), sondern nur eine Basisklasse Ihrer Entitäten. Andernfalls wäre die Lösung von @Paul Keister einfacher.

    Bearbeiten

    Alternativ können Sie auch Folgendes versuchen :

     public static class MyExtensions
    {
        public static int? GetId(this Context db, Type entityType, string name)
        {
            return ((IQueryable<DomainEntity>)db.Set(entityType))
                .Where(x => x.Name == name)
                .Select(x => (int?)x.Id)
                .FirstOrDefault();
        }
    }
     

    Und nennen Sie es:

     int? id = db.GetId("abc", someType);
     

    Eine Ausnahme wird zur Laufzeit ausgelöst, wenn someType nicht von DomainEntity erbt. Die generische Version prüft dies zur Kompilierzeit. Wenn Sie also die erste Version bevorzugen können,

    23 November 2011
    Slauma
  • Das erste Konstrukt funktioniert nicht, da Sie mit einem nicht generischen DbSet arbeiten. Daher können Sie die FirstOrDefault-Erweiterungsmethode nicht anwenden, die nur mit einem Generic funktioniert. Es klingt, als ob Sie das bereits verstehen, weil Sie bereits versuchen, das nicht generische DbSet zu erhalten. Der Fehler, den Sie mit der Cast () -Methode erhalten, wird durch Ihren Versuch verursacht, ein DbSet in ein DbSet umzuwandeln. Dies kann nicht zulässig sein, da ansonsten DbSet (andere Objekte als WindowsStyle) nichtkonforme Mitglieder hinzugefügt werden könnten. Eine andere Möglichkeit, dies zu sagen, ist, dass Kovarianz für DbSets nicht unterstützt wird, da DbSets Ergänzungen zulässt.

    Ich denke, Sie müssen einen anderen Weg finden, um das zu tun, was Sie versuchen . Das Mischen von LINQ und Vererbung auf diese Weise ist offensichtlich problematisch. Da Sie einen Basistyp definiert haben und nur mit Attributen arbeiten, die für den Basistyp verfügbar sind, können Sie den Basistyp nicht einfach abfragen.

         public static int GetId(this Context db, string name)
        {
            return db.DomainEntities.FirstOrDefault(x => x.Name == name).Id;
        }
     

    Sie machen sich wahrscheinlich Sorgen um Namenskollisionen zwischen den verschiedenen Typen, aber Sie können wahrscheinlich damit beginnen und sich die abgeleiteten Typzuordnungen ansehen, um sich zu vergewissern, dass Sie den richtigen Typ sehen. Eine Möglichkeit, dies zu umgehen, besteht darin, Ihrer DomainEntity-Definition ein Typflag hinzuzufügen.

    07 January 2012
    Paul Keister
  • Hier ist das Problem. Die Klasse DbSet hat eine eigene Implementierung von Cast<T>() , die NUR Datenbanktypen zulässt (wie Cast<WindowStyle>()), sodass diese Methode Cast<DomainEntity>() nicht zulässt und die Ausnahme auslöst.

    Stattdessen möchten Sie die Erweiterungsmethode IQueryable.Cast<T>() verwenden, mit der Ihre Daten einfach in den Basistyp umgewandelt werden. Hier ein Beispiel:

     var set = ((IQueryable)db.Set(type)).Cast<DomainEntity>();
    return set.First(x => x.Name == name).Id;
     
    22 November 2011
    Scott Rippey
  • Hier ist eine Idee, die scheinbar funktioniert.

     public static int GetId(this Context db, Type type, string name)
    {
        var set = db.Set(type);
        foreach (dynamic entry in set)
            if (entry.Name == name)
                return entry.Id; 
    }
     
    05 July 2013
    ShimmyDavid Makogon
  • Versuchen Sie es etwas umzukehren

    . Wo (x = & gt; x.Name == Name) ) .FirstOrDefault (); 
     

    Ihre geben ein Null-Objekt zurück und versuchen dann, die ID daraus zu erhalten

    22 November 2011
    Adam Tuliper - MSFT