LINQ to Entities 不支持指定的类型成员。仅支持初始值设定项、实体成员和实体导航属性

问题描述 投票:0回答:8
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”。 仅初始值设定项、实体成员和实体导航属性 支持。

年龄不在数据库中,它是我在 clsProfileDate 类中创建的属性,用于根据出生日期计算年龄。有什么解决办法吗?

entity-framework-4 linq-to-entities
8个回答
115
投票

您不能在

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

27
投票

很多人会说这是一个糟糕的答案,因为它不是最佳实践,但你也可以在你的位置之前将其转换为列表。

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

Slauma 的答案更好,但这也可以。这会花费更多,因为 ToList() 将对数据库执行查询并将结果移至内存中。


19
投票

当您不小心忘记为属性定义 setter 时,您也会收到此错误消息。 例如:

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

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

调用 ToList 也会给出同样的错误消息。这是一个非常微妙的错误,很难被发现。


4
投票

就我而言,我仅在生产中收到此错误消息,但在本地运行时却没有收到此错误消息,即使我的应用程序的二进制文件是相同的。

在我的应用程序中,我使用自定义

DbModelStore
,以便将运行时生成的 EDMX 保存到磁盘并在启动时从磁盘加载(而不是从头开始重新生成),以减少应用程序启动时间 - 并且由于我的代码中存在一个错误,我没有使磁盘上的 EDMX 文件无效 - 因此生产使用的是磁盘中旧版本的 EDMX 文件,该文件引用了我在异常中重命名类型名称之前的应用程序类型的旧版本错误信息。

删除缓存文件并重新启动应用程序即可修复该问题。


3
投票

我忘记选择列(或将属性设置/映射到列值):

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

调用

queryable.OrderBy("Id")
会抛出异常,即使
DataModel
定义了属性
Id

正确的查询是:

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

1
投票

高级答案:

在 edmx 文件中搜索

EntitySetMapping
并检查该字段是否映射到数据库中的列:

<EntitySetMapping Name="MY_TABLE">
    <EntityTypeMapping TypeName="MYMODEL.MY_TABLE">
      <MappingFragment StoreEntitySet="MY_TABLE">
        <ScalarProperty Name="MY_COLUMN" ColumnName="MY_COLUMN_NAME" />
      </MappingFragment>
    </EntityTypeMapping>
  </EntitySetMapping>

我遇到这个问题是因为 edmx 进行了我不想要的更改,并且通过 git 我丢弃了太多更改...


0
投票

就我而言,我忘记声明没有 getter 和 setter 的属性。


-1
投票

在 WHERE 子句之前检查 Count() 解决了我的问题。它比 ToList() 便宜

if (authUserList != null && _list.Count() > 0)
    _list = _list.Where(l => authUserList.Contains(l.CreateUserId));
© www.soinside.com 2019 - 2024. All rights reserved.