【问题标题】:Linq query errorLinq 查询错误
【发布时间】:2011-04-21 16:26:37
【问题描述】:

我正在使用以下 Linq 查询:

from p in People
 where p.Name == "George Lucas"
select p.TitlesActedIn

其中 TitlesActedIn 是一个列表。 People 和 TitlesActedIn 是关联的

但我收到错误:

InvalidCastException:无法将“System.Linq.Expressions.PropertyExpression”类型的对象转换为“System.Data.Services.Client.ResourceExpression”类型。

请提出解决方案。

【问题讨论】:

  • 围绕您的查询发布整个语句。您将查询分配给什么?
  • 这是 LINQ to SQL 吗? People来自哪里?
  • 看起来像 DataService 客户端 api。
  • 我需要返回乔治·卢卡斯执导的所有电影的列表。
  • 人物和片名/电影是两个实体

标签: linq wcf-data-services linqpad


【解决方案1】:

一个非常简单的方法:

var query = People
    .Expand("TitlesActedIn")
    .Where(p => p.Name == "George Lucas")
    .First()
    .TitlesActedIn.Select(t => t.ShortName);              
query.Dump();

重要的是要注意,如果您传递的名称不存在,这将崩溃。 (First Operator 会抛出异常。您需要保证名称存在,或者分两步进行。


如果您想一步完成,归结为:(请注意返回的内容)

http://odata.netflix.com/catalog/People()?$filter=Name eq 'George Lucas'&$top=1&$expand=TitlesActedIn

您需要展开,否则在.First() 之后它将退出评估,因为 TitlesActedIn 将为空。

它基本上翻译为选择 Person,包含(扩展)TitlesActedIn 关联,然后选择名称(客户端)

这样做的缺点是您要从 Titles 表中拉回所有内容(所有字段)。因此,对于与要返回的人员相关的每个标题(标题、年份、描述、短名称等)。

如果您在两个查询中执行此操作,则只能从 TitlesActedIn 关联中拉回“ShortName”。

【讨论】:

  • 在这种情况下,这确实是一个很好的答案。但我认为我们应该小心使用 Expand 这样的......重要的是要了解您获得的数据比您实际需要的多得多。例如,在移动平台上,两个查询可能会更好。
  • 你能告诉我你为什么使用 Expand 吗?
  • 感谢您添加对数据成本的澄清。你得到了我的 +1
【解决方案2】:

已更新:请参阅question and answer 以了解 Select Many in Data Services 的限制 + 另一种基于 $expand 的解决方案(注意这需要服务器支持 expand )

如果这是 WCF 数据服务,并且 TitlesActedIn 是相关电影的集合。 只有当 Person.Name 是主键时,您才能在一个查询中执行此操作。

为了说明这一点:

var titles = from p in people
             where p.Name == "George Lucas"
             from m in p.TitlesActedIn
             select m;

会做你想做的事,但前提是 Name 是 Person 实体的键,否则不支持。

如果名称不是关键的一种方法(今天)是使用两个查询,如下所示:

var key = (from p in people
          where p.Name == "George Lucas"
          select new {p.Id}).Single().Id;

var titles = from p in people
             where p.Id == key
             from m in p.TitlesActedIn
             select m;

另一种选择是展开:

var george = (from p in people.Expand("TitlesActedIn")
             where p.Name == "George Lucas"
             select p).Single();

var titles = george.TitlesActedIn;

但这依赖于支持 $expand 的服务器 - 并非所有服务器都支持...

请注意,我们目前正在努力添加 any/all support to OData 和 WCF 数据服务,一旦发布,您就可以编写:

var titles = from t in titles
             where t.Actors.Any(a => a.Name == "George Lucas")
             select t;

希望对你有帮助

注意:在为 George Lucas 获取密钥的代码中,我创建了一个匿名类型,因为目前 WCF 数据服务不支持直接实现基元。

【讨论】:

  • 我使用了第一个查询,我得到“NotSupportedException Can only specify query options (orderby, where, take, skip) after last navigation”
  • 是的,那是因为 Name 不是 netflix 目录中的键,所以您需要发出两个查询...根据我建议的解决方法
  • 我可以使用子查询组合这两个查询吗?如果是这样我如何用查询替换键。我说的是你的第二个解决方案
  • 不。但另一种选择是尝试扩展查询......然后你可以使用贾斯汀的代码......
  • 其实我只是在我的答案中添加了 $expand 解决方案......也许这是你最好的选择。
【解决方案3】:

有趣的是,以下工作:

from p in People
where p.Name == "George Lucas"
select new { p.TitlesActedIn }

就像这样:

(from p in People
where p.Name == "George Lucas"
select new { p.TitlesActedIn }).First().TitlesActedIn

WCF 客户端在 URI 翻译中自动添加扩展调用:

http://odata.netflix.com/Catalog/People()?$filter=Name eq 'George Lucas'&$top=1&$expand=TitlesActedIn&$select=TitlesActedIn/*

【讨论】:

    【解决方案4】:

    如果我使用 group by 子句和 lambda 表达式来使用 WCF 数据服务获取数据,我会收到类似的错误。我知道 WCF 数据服务不支持某些操作。请确保您没有使用不受支持的 LINQ 操作。

    http://msdn.microsoft.com/en-us/library/ee622463.aspx

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多