Linq在.Substring()上抛出异常

时间:2010-12-14 13:54:04

标签: c# .net linq entity-framework substring

我有一种情况需要让我的LINQ to Entities查询返回一个子串,具体取决于字符串的长度。 这是查询:

var query = (
    from f in Context.Files
    orderby f.DateAdded descending
    select new
    {
        Concerns = f.Concerns.Name,
        Sender = f.Sender.Name,
        CategoryCount = f.Categories.Count(),
        DateAdded = f.DateAdded,
        Comment = (f.Comment == null || f.Comment.Length < 5) 
            ? f.Comment : f.Comment
    }).Take(10);

所以我正在做的是获取最后10个类型为Files的实体,然后从中选择一组属性以显示在listview中。有些是简单的字符串(Concerns,Sender)。 CategoryCount返回与File对象关联的类别数。

但是,如果评论长度超过给定长度,我希望评论被截断。在上面的代码中,一切正常。现在当我更换这一行时:

Comment = (f.Comment == null || f.Comment.Length < 5) 
    ? f.Comment : f.Comment

这一行:

Comment = (f.Comment == null || f.Comment.Length < 5) 
    ? f.Comment : f.Comment.SubString(0,5)

应用程序抛出XamlParseException(???)

  

在类型'DocumentManager.Views.ListEntriesView'上调用与指定绑定约束匹配的构造函数引发异常

我真的不知道为什么会这样做。 LINQ中不支持SubString方法吗?

希望有人可以帮助我。在那之前,我将保持原样。

编辑2(不知何故,我的第一次编辑迷失了。所以我正在重做它): 根据我得到的评论,我将代码更改为此,现在可以使用了:

var query = App.Context.Files.OrderByDescending(File => File.DateAdded).Take(10).AsEnumerable()
            .Select(File => new
            {
                Concerns = File.Concerns.Name,
                Sender = File.Sender.Name,
                CategoryCount = File.Categories.Count(),
                DateAdded = File.DateAdded,
                Comment = (File.Comment == null || File.Comment.Length < 100) ? File.Comment : File.Comment.Substring(0, 100) + "..."
            });

我忘了提到我正在使用SQLite。因此,在SQLite EF Provider中可能没有实现Substring。

4 个答案:

答案 0 :(得分:3)

实际上并不是LINQ的错。您的模型绑定到IQueryable,即数据库直接支持的例程(其他一切都抛出异常)。您应该在某些时候使用AsEnumerable方法来完成其他任务。

阅读更多内容,比尔瓦格纳解释了IQueryable和IEnumerable之间的区别:

http://msdn.microsoft.com/en-us/vcsharp/ff963710

答案 1 :(得分:2)

我不确定,但我怀疑Linq-to-Entities不支持子字符串。我会将你的Take(10)移到你的select语句之前,然后在Take(10)之后调用AsEnumerable(),之后你的select语句。这将导致您从数据库中撤回一组文件,然后投影将在内存中完成。

答案 2 :(得分:1)

这似乎是SQLite解析器中的一个错误,因为

  • Substring正常工作,可以使用LINQ to Entities查询到SQL Server数据库

  • 如果您查看生成的SQL日志,它会将其生成为子串SQL函数

  • 在SQLite中,正确的函数是substr,而不是substring

因此,生成查询的方式存在错误。

以下是修复此错误的方法。

在您的数据库模型中,在EntityContainer

之前添加此代码
<Function Name="substr" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="true" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo" ReturnType="nvarchar">
  <Parameter Name="text" Type="nvarchar" Mode="In" />
  <Parameter Name="startPos" Type="int" Mode="In" />
</Function>

在您的上下文类(在其旁边创建一个分部类)中,添加此代码

[DbFunction("MyModel.Store", "substr")]
public string SubStr(string text, int startPos) {
    return text.Substring(startPos);
}

在您的代码中,以这种方式调用Substring

context.SubStr(text, startpos)

现在它将正确映射到SUBSTR函数而不是SUBSTRING!它与映射用户定义函数类似,只是我们映射到现有的标准函数。

希望这有帮助!

答案 3 :(得分:0)

正确 - LINQ不支持子字符串,但是当您尝试这样的事情时,异常并不总是非常清楚。