web-dev-qa-db-ja.com

指定されたタイプメンバーは、LINQ to Entitiesではサポートされていません。初期化子、エンティティメンバー、およびエンティティナビゲーションプロパティのみがサポートされます

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);
}

ここで私は例外を受け取っています:

指定されたタイプメンバー「年齢」は、LINQ to Entitiesではサポートされていません。初期化子、エンティティメンバー、およびエンティティナビゲーションプロパティのみがサポートされています。

Ageがデータベースにない場合、DOBからAgeを計算するためにclsProfileDateクラスで作成したプロパティです。これに対する解決策はありますか?

63
Sarang Amrutkar

Where式のデータベース列にマップされていないプロパティは使用できません。次のようなマップされたプロパティに基づいて式を作成する必要があります。

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

マッピングされていないAgeプロパティの代わりとして、この式を次のような静的メソッドに抽出できます。

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;
    }
}

そして、次のように使用します:

result = result.Where(clsProfileDate.IsOlderThan(from));
85
Slauma

多くの人がこれは悪い答えだと言うでしょう。なぜならそれはベストプラクティスではないが、あなたはそれをあなたの場所の前にリストに変換することもできるからです。

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

Slaumaの答えは優れていますが、これも同様に機能します。 ToList()はデータベースに対してQueryを実行し、結果をメモリに移動するため、これにはさらにコストがかかります。

19
Tony

また、プロパティのセッターを誤って定義したことを忘れた場合にも、このエラーメッセージが表示されます。例えば:

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

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

ToListを呼び出すと、同じエラーメッセージが表示されます。これは非常に微妙なエラーであり、検出が非常に困難です。

10
Marcel Gelijk

列を選択するのを忘れました(または、プロパティを列の値に設定/マッピングします):

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

DataModelにプロパティIdが定義されていても、queryable.OrderBy("Id")を呼び出すと例外がスローされます。

正しいクエリは次のとおりです。

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

この場合、最も簡単で最良のアプローチの1つは、最初にlistにキャストしてからwhereまたはselectを使用することです。

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