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

84
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”。 只支持初始化程序、实体成员和实体导航属性。

其中 Age 不是数据库中存在的字段,而是我在 clsProfileDate 类中创建的属性,用于从 DOB(出生日期)计算年龄。有什么解决方法吗?

7个回答

114

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

除了检查下面hp93的答案之外,在这个可查询对象中,您必须明确指定您想在“Where”中使用的所有属性,因此在这里,您只能按A过滤、分组或排序,因为您只有A的映射 - A = a.A - Nikita

26
很多人会认为这个答案不好,因为它不是最佳实践,但在where之前,您也可以将其转换为List。
result = result.ToList().Where(p => date >= p.DOB);

Slauma的回答更好,但这个也可以。这个会更加昂贵,因为ToList()将执行数据库中的查询并将结果移动到内存中。


4
感觉肮脏,但适量使用效果不错。 - AGB
13
当调用 ToList 方法时,查询将被执行并且不必要的数据将被加载到内存中。因此,在编码时最好设定一些限制! - Paridokht
这对我很有好处,因为我的问题属性在Sum Linq函数中而不是Where子句中。因此,我没有获取不必要的数据,并且在检索到的数据上执行Linq Sum函数,该函数适用于列表。谢谢!一开始可能看起来不好,但在某些情况下非常有帮助! - Dov Miller
这对我非常有效,因为我们正在修改其中一个字段,在另一个字段中基于布尔值在其前面添加数据(标记项目已停用)。在我加入 tolist 之前,它一直无法正常工作。 - John Lord
正是我所需要的! - Sharif Yazdian
很想将其点踩,但不会这么做,因为答案并没有错,只是不够好。 - nawfal

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方法将导致相同的错误消息。这是一个非常微妙的错误,很难检测到。


在一些愚蠢的重构之后,这就是我得到的结果。 - Phil Cooper
1
但如果它是一个不可更新的SQL视图,我为什么需要setter呢? - ARLibertarian
1
这并不重要。Entity Framework 仍然需要一种设置属性的方式。在普通的 C# 代码中,您无法像这样做:Building b = new Building(); b.Description = "test"; - Marcel Gelijk

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丢弃了太多的更改...


-1
在 WHERE 子句之前检查 Count() 解决了我的问题。这比 ToList() 更便宜。
if (authUserList != null && _list.Count() > 0)
    _list = _list.Where(l => authUserList.Contains(l.CreateUserId));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接