简体   繁体   English

Linq在.Substring()上引发异常

[英]Linq throws exception on .Substring()

I've got a situation where I need to have my LINQ to Entities query return a substring depending on the length of the string. 我有一种情况,我需要让我的LINQ to Entities查询根据字符串的长度返回一个子字符串。 Here's the Query: 这是查询:

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

So what I'm doing is getting the last 10 added Entities of type Files and then select a set of properties from it to display inside a listview. 因此,我正在做的是获取文件类型最后10个添加的实体,然后从中选择一组属性以显示在列表视图中。 Some are plain strings (Concerns, Sender). 一些是纯字符串(关注,发件人)。 CategoryCount returns the number of categories which are associated with the File object. CategoryCount返回与File对象关联的类别数。

However, I want the comment to be truncated if it is longer then a given length. 但是,如果长度大于给定的长度,我希望将其截断。 In the above code, everything is working correctly. 在上面的代码中,一切正常。 Now when I replace this line: 现在,当我替换此行时:

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

With this line: 用这行:

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

the application throws a XamlParseException (???) 应用程序抛出XamlParseException(???)

The invocation of the constructor on type 'DocumentManager.Views.ListEntriesView' that matches the specified binding constraints threw an exception 匹配指定绑定约束的类型为'DocumentManager.Views.ListEntriesView'的构造方法的调用引发了异常

I really don't know why it would do that. 我真的不知道为什么会那样做。 Is the SubString method not supported in LINQ? LINQ不支持SubString方法吗?

Hope someone can help me here. 希望有人可以在这里帮助我。 Until then, I'll just leave it the way it is. 在那之前,我将保持现状。

EDIT 2 (Somehow, my first edit got lost. So I'm redoing it): Based on the comments I got I changed my code to this and it works now: 编辑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) + "..."
            });

I forgot to mention that I'm using SQLite. 我忘了提到我正在使用SQLite。 So maybe Substring is not implemented in the SQLite EF Provider. 因此,也许在SQLite EF提供程序中未实现子字符串。

It's not LINQ's fault actually. 实际上这不是LINQ的错。 Your model is bind to IQueryable, ie the routines directly supported by your database (everything else throws Exceptions). 您的模型绑定到IQueryable,即数据库直接支持的例程(其他所有抛出异常)。 You should use AsEnumerable method at some point to do everything else. 您应该在某个时候使用AsEnumerable方法来执行其他所有操作。

Read more as Bill Wagner explains difference between IQueryable and IEnumerable here: 在Bill Wagner在这里解释IQueryable和IEnumerable之间的区别时,请阅读更多内容:

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

I don't know for sure, but I would suspect substring isn't supported by Linq-to-Entities. 我不确定,但是我怀疑Linq-to-Entities不支持子字符串。 I would move your Take(10) to before your select statement, then after Take(10) call AsEnumerable(), then have your select statement after that. 我将把Take(10)移到select语句之前,然后在Take(10)之后调用AsEnumerable(),然后在那之后使用select语句。 That will cause you to pull back a collection of Files from the database, then the projection will be done in-memory. 这将导致您从数据库中拉回文件的集合,然后将在内存中进行投影。

This appears to be a bug in the SQLite parser because 这似乎是SQLite解析器中的错误,因为

  • Substring works correctly to query into a SQL Server database with LINQ to Entities 子字符串可以正常工作,以使用LINQ to Entities查询SQL Server数据库

  • If you look in the generated SQL log, it generates it as Substring SQL function 如果查看生成的SQL日志,它将作为Substring SQL函数生成

  • In SQLite, the correct function is substr, not substring 在SQLite中,正确的函数是substr,而不是substring

Thus, there is a bug in the way it is generating the query. 因此,在生成查询的方式中存在一个错误。

Here's a way to fix this bug. 这是修复此错误的一种方法。

In your database model, add this code right before EntityContainer 在您的数据库模型中,在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>

In your context class (create a partial class next to it), add this code 在您的上下文类中(在它旁边创建一个局部类),添加以下代码

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

In your code, call Substring in this way 在您的代码中,以这种方式调用Substring

context.SubStr(text, startpos)

It will now properly map to the SUBSTR function instead of SUBSTRING! 现在它将正确映射到SUBSTR函数,而不是SUBSTRING! It's like mapping a User Defined Function, except that we map to an existing standard function. 就像映射用户定义函数一样,不同之处在于我们映射到现有的标准函数。

Hope this helps! 希望这可以帮助!

正确-LINQ不支持子字符串,但是不幸的是,当您尝试此类操作时,从异常中并非总是很清楚。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM