【问题标题】:Selecting Partial Substring in a LINQ在 LINQ 中选择部分子字符串
【发布时间】:2016-10-24 18:15:25
【问题描述】:

我有一个记录如下的表:

ID     VirtualPath
1      ~/Root/FirstFolder
2      ~/Root/FirstFile.ext
3      ~/Root/SecondFolder
4      ~/Root/SecondFolder/AnotherFile.ext
5      ~/Root/SecondFolder/YetAnotherFile.ext
6      ~/Root/SecondFolder/3rdLevelFolder
7      ~/Root/SecondFolder/3rdLevelFolder/StillAnotherFile.ext

我需要一个 LINQ 查询,所以当我传递“~/Root/SecondFolder/”的参数时,我得到#s 4,5 & 6,但不是 3 也不是 7。 当您使用 Window 的资源管理器时,它是镜像,(忽略树视图)您只能看到当前目录的内容。 这甚至可能吗?

以下工作,但我不知道如何将其转换为 LINQ,当我尝试在我的应用程序中运行 SQL 命令时,EF 不太喜欢它:

DECLARE @path NVARCHAR(255) = '~/Root/SecondFolder/%'

SELECT [ID],[VirtualPath]
  FROM [dbo].[Files] 
  WHERE VirtualPath LIKE @path
AND LEN(LEFT([VirtualPath], LEN([VirtualPath]) - (CHARINDEX('/', REVERSE([VirtualPath])) - 1))) < (LEN(@path) + 1)

我无法在应用程序中过滤它,因为可能有数千条记录。

请提前告知并感谢您。

【问题讨论】:

  • 为什么不为这种复杂的查询创建一个存储过程,并通过EF调用它,然后将结果转换为所需的对象?
  • 使用 EntityFramework 的查询方式有很多种。你能说明你已经完成了多远,以及你在哪里卡住了吗?
  • 查看EntityFunctions中的规范函数
  • 真正的诀窍是确定哪些函数将使用 EF 转换为 SQL,如果您需要的东西不受支持,那么您可能需要考虑使用 AsEnumerable,然后在 Linq 中进行进一步过滤-to-Objects。

标签: c# sql entity-framework linq sql-server-2008


【解决方案1】:

可能有更好的方法来编写此 LINQ express,但这应该可以:

string param = "~/Root/SecondFolder/";
string[] filter = files.Where(x => (x.StartsWith(param) && !x.Substring(param.Length, x.Length - param.Length).Contains('/'))).ToArray();

性能限制来自拆分字符串。这是我能想到的确保您在正确目录中的唯一方法。

也许其他人会想出更好的写法。

已编辑:实体框架不支持拆分字符串。创建了一个更丑陋的查询,但仍然有效。

【讨论】:

  • 我很确定 Split 不受 EF 支持。
  • 啊,那是真的。我改变了查询。我想知道您是否可以计算字符或做一些比确保子字符串不包含正斜杠更好的事情。
  • A. Bello,请原谅我的无知,但 Startswith、Substring 和 Length 不可用,只有表的列名和一些额外的属性?
  • @Darkloki StartsWithSubstringLength 在 EF 中都可用。
【解决方案2】:

它不漂亮,但我相信这行得通。

            var path = "~/Root/SecondFolder/";
            var rezults = (from f in context.Files
                          where f.VirtualPath.StartsWith(path)
                          && (f.VirtualPath.Length - f.VirtualPath.Replace("/", string.Empty).Length <= (path.Length - path.Replace("/", string.Empty).Length))
                          select new 
                          {
                              f.Id, 
                              f.VirtualPath
                          }

我头上的伪代码看起来像......

select Id,VirtualPath
from Files
where VirtualPath starts with my query path
and VirtualPath has <= slashes than my query pathy
--aka do a non-recursive listing of my folder

【讨论】:

    【解决方案3】:

    我认为这个变体代码干净易读:

    var folderPath = @"~/Root/SecondFolder/";
    var results = context.Files
        .Where(f => f.VirtualPath.StartsWith(folderPath))
        .Where(f => !f.VirtualPath.Substring(folderPath.Length).Contains("/"))
        .Select(f => new { ID = f.Id, VirtualPath = f.VirtualPath})
        .ToList();
    

    它只是确保值以所需路径开头,然后确保剩余内容中没有斜线。

    Entity Framework 似乎可以很好地翻译它并生成以下内容:

    DECLARE @p__linq__0 nvarchar(4000)
    DECLARE @p__linq__1 nvarchar(4000)
    
    SET @p__linq__0 = N'~~/Root/SecondFolder/%'
    SET @p__linq__1 = N'~/Root/SecondFolder/'
    
    SELECT 
        [Extent1].[ProductID] AS [ProductID], 
        [Extent1].[ProductName] AS [ProductName]
    FROM [dbo].[Products] AS [Extent1]
    WHERE ([Extent1].[ProductName] LIKE @p__linq__0 ESCAPE N'~')
    AND NOT (SUBSTRING([Extent1].[ProductName], (CAST(LEN(@p__linq__1) AS int)) + 1, (LEN([Extent1].[ProductName])) - (CAST(LEN(@p__linq__1) AS int))) LIKE N'%/%')
    

    .. 比您最初提出的 SQL 略长,但也不是一百万英里。

    【讨论】:

      猜你喜欢
      • 2018-04-15
      • 2018-09-07
      • 2018-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-01
      • 2013-05-21
      • 1970-01-01
      相关资源
      最近更新 更多