Das angegebene Typmitglied wird in LINQ to Entities nicht unterstützt. Es werden nur Initialisierer, Entitätsmitglieder und Entitätsnavigationseigenschaften unterstützt

71
var result =
    (from bd in context.tblBasicDetails
     from pd in context.tblPersonalDetails.Where(x => x.UserId == bd.UserId).DefaultIfEmpty()
     from opd in context.tblOtherPersonalDetails.Where(x => x.UserId == bd.UserId).DefaultIfEmpty()
     select new clsProfileDate()
     {
         DOB = pd.DOB
     });

foreach (clsProfileDate prod in result)
{
    prod.dtDOB = !string.IsNullOrEmpty(prod.DOB) ? Convert.ToDateTime(prod.DOB) : DateTime.Today;
    int now = int.Parse(DateTime.Today.ToString("yyyyMMdd"));
    int dob = int.Parse(prod.dtDOB.ToString("yyyyMMdd"));
    string dif = (now - dob).ToString();
    string age = "0";
    if (dif.Length > 4)
    age = dif.Substring(0, dif.Length - 4);
    prod.Age = Convert.ToInt32(age);
}

GetFinalResult(result);

protected void GetFinalResult(IQueryable<clsProfileDate> result)
{
    int from;
    bool bfrom = Int32.TryParse(ddlAgeFrom.SelectedValue, out from);
    int to;
    bool bto = Int32.TryParse(ddlAgeTo.SelectedValue, out to);

    result = result.AsQueryable().Where(p => p.Age >= from);
}

Hier bekomme ich eine Ausnahme:

Das angegebene Typmitglied "Alter" wird in LINQ to Entities nicht unterstützt. Es werden nur Initialisierer, Entitätsmitglieder und Entitätsnavigationseigenschaften unterstützt.

Wenn sich das Alter nicht in der Datenbank befindet, ist es eine Eigenschaft, die ich in der Klasse clsProfileDate erstellt habe, um das Alter aus dem Geburtsdatum zu berechnen. Irgendeine Lösung dafür?

Sarang Amrutkar
quelle

Antworten:

99

Sie können keine Eigenschaften verwenden, die keiner Datenbankspalte in einem WhereAusdruck zugeordnet sind. Sie müssen den Ausdruck basierend auf zugeordneten Eigenschaften erstellen, z.

var date = DateTime.Now.AddYears(-from);
result = result.Where(p => date >= p.DOB);
// you don't need `AsQueryable()` here because result is an `IQueryable` anyway

Als Ersatz für Ihre nicht zugeordnete AgeEigenschaft können Sie diesen Ausdruck in eine statische Methode wie folgt extrahieren:

public class clsProfileDate
{
    // ...
    public DateTime DOB { get; set; } // property mapped to DB table column

    public static Expression<Func<clsProfileDate, bool>> IsOlderThan(int age)
    {
        var date = DateTime.Now.AddYears(-age);
        return p => date >= p.DOB;
    }
}

Und dann benutze es so:

result = result.Where(clsProfileDate.IsOlderThan(from));
Slauma
quelle
Überprüfen Sie außerdem die unten stehende Antwort von hp93. from a in db.aitems select new Model { A = a.A }Hier in dieser Abfrage können Sie genau alle Eigenschaften angeben, die Sie verwenden möchten Where, damit Sie hier filtern oder gruppieren oder nur nach A sortieren können, da Sie nur eine Zuordnung für A -A = a.A
Nikita
20

Viele Leute werden sagen, dass dies eine schlechte Antwort ist, da dies keine bewährte Methode ist. Sie können sie jedoch auch in eine Liste vor Ihrem Aufenthaltsort konvertieren.

result = result.ToList().Where(p => date >= p.DOB);

Slaumas Antwort ist besser, aber das würde auch funktionieren. Dies kostet mehr, da ToList () die Abfrage für die Datenbank ausführt und die Ergebnisse in den Speicher verschiebt.

Tony
quelle
4
Fühlte sich schmutzig an, aber wirksam in kleinen Dosen.
AGB
9
Beim ToListAufruf wird die Abfrage ausgeführt und unnötige Daten werden in den Speicher geladen. Es ist also besser, einige Grenzen bei der Codierung zu haben!
Paridokht
Dies ist gut für mich, da sich meine problematische Eigenschaft in einer Sum Linq-Funktion befindet, die nicht in der Where-Klausel enthalten ist. Ich erhalte also keine unnötigen Daten und mache auf den empfangenen Daten die Linq-Summenfunktion, die an der Liste arbeitet. Vielen Dank! Was auf den ersten Blick schlecht aussieht, kann in bestimmten Situationen sehr hilfreich sein!
Dov Miller
Dies hat für mich hervorragend funktioniert, da wir eines der Felder so ändern, dass Daten basierend auf einem Booleschen Wert in einem anderen Feld vorangestellt werden. (Markieren von Elementen deaktiviert) und es weigerte sich zu arbeiten, bis ich eine Tolist in die Mitte steckte.
John Lord
Genau das, was ich brauchte!
Sharif Yazdian
14

Diese Fehlermeldung wird auch angezeigt, wenn Sie versehentlich vergessen haben, einen Setter für eine Eigenschaft zu definieren. Zum Beispiel:

public class Building
{
    public string Description { get; }
}

var query = 
    from building in context.Buildings
    select new
    {
        Desc = building.Description
    };
int count = query.ToList();

Der Aufruf von ToList gibt dieselbe Fehlermeldung aus. Dieser ist ein sehr subtiler Fehler und sehr schwer zu erkennen.

Marcel Gelijk
quelle
Nach einigem dummen Umdenken hat mich das dazu gebracht.
Phil Cooper
1
Aber wenn es sich um eine nicht aktualisierbare SQL-Ansicht handelt, warum sollte ich den Setter benötigen?
ARLibertarian
1
Das spielt keine Rolle. Entity Framework benötigt noch eine Möglichkeit, die Eigenschaft festzulegen. Im normalen C # -Code können Sie Folgendes nicht tun: Gebäude b = neues Gebäude (); b.Description = "test";
Marcel Gelijk
2

Ich habe vergessen, die Spalte auszuwählen (oder die Eigenschaft einem Spaltenwert zuzuordnen):

IQueryable<SampleTable> queryable = from t in dbcontext.SampleTable
                                    where ...
                                    select new DataModel { Name = t.Name };

Beim Aufruf queryable.OrderBy("Id")wird eine Ausnahme ausgelöst, obwohl DataModeldie Eigenschaft Iddefiniert ist.

Die richtige Abfrage lautet:

IQueryable<SampleTable> queryable = from t in dbcontext.SampleTable
                                    where ...
                                    select new DataModel { Name = t.Name, Id = t.Id };
Hp93
quelle
2

In meinem Fall wurde diese Fehlermeldung nur in der Produktion angezeigt, jedoch nicht, wenn sie lokal ausgeführt wurde, obwohl die Binärdateien meiner Anwendung identisch waren.

In meiner Anwendung verwende ich eine benutzerdefinierte Funktion,DbModelStore damit das zur Laufzeit generierte EDMX auf der Festplatte gespeichert und beim Start von der Festplatte geladen wird (anstatt es von Grund auf neu zu generieren), um die Startzeit der Anwendung zu verkürzen - und aufgrund eines Fehlers in meinem Code I. Die EDMX-Datei auf der Festplatte wurde nicht ungültig. Daher verwendete Production eine ältere Version der EDMX-Datei von der Festplatte, die auf eine ältere Version der Typen meiner Anwendung verwies, bevor ich den Typnamen in der Ausnahmefehlermeldung umbenannte.

Durch Löschen der Cache-Datei und Neustarten der Anwendung wurde das Problem behoben.

Dai
quelle
1

In diesem Fall besteht einer der einfachsten und besten Ansätze darin, es zuerst zu besetzen listund dann whereoder zu verwenden select.

result = result.ToList().where(p => date >= p.DOB);
Arash MAS
quelle
0

Das Überprüfen von Count () vor der WHERE-Klausel hat mein Problem gelöst. Es ist billiger als ToList ()

if (authUserList != null && _list.Count() > 0)
    _list = _list.Where(l => authUserList.Contains(l.CreateUserId));
Bengü Hasdil
quelle