EF 6环境下WinForms应用的LINQ查询实现:文件路径过滤与按文件大小排序
解决EF6 LINQ排序错误及实现需求查询
首先,咱们先搞清楚你遇到的错误原因:你写的OrderBy(movie => movie.files.Any(f => f.size))里,Any()方法返回的是布尔值(true/false,表示是否存在符合条件的文件),但OrderBy需要的是一个用来排序的具体键值(比如文件的size字符串),两者类型不匹配,所以编译器报了CS1662错误。
接下来分两种场景给你提供正确的LINQ写法,对应你可能的需求:
场景1:和原SQL一致,返回所有影片-文件关联记录(每行一个影片+符合条件的文件),按文件size排序
原SQL是把每个符合条件的影片-文件组合作为独立行返回,用EF的导航属性可以这样实现:
var movieFileDetails = context.movies // 把每个影片拆分成它的符合条件的文件条目 .SelectMany(movie => movie.files .Where(file => file.path.StartsWith(@"M:\")) // 投影出你需要的字段,和原SQL的SELECT对应 .Select(file => new { MovieTitle = movie.title, FilePath = file.path, FileSize = file.size })) // 按文件的size字段排序(注意:因为size是字符串,会按字典序排序) .OrderBy(result => result.FileSize) .ToList();
如果需要返回完整的movie和file实体,而不是自定义匿名类,可以改成:
var movieFilePairs = context.movies .SelectMany(movie => movie.files .Where(file => file.path.StartsWith(@"M:\")) .Select(file => new { Movie = movie, File = file })) .OrderBy(pair => pair.File.size) .ToList();
场景2:返回去重的影片(每个影片仅出现一次),按关联文件的size排序
如果你的需求是获取所有关联了M:\开头文件的影片,并且按这些文件的某个size(比如最大size、最小size)排序,需要明确排序的依据。比如按关联文件的最大size排序:
var filteredMovies = context.movies // 筛选出关联了M:\开头文件的影片 .Where(movie => movie.files.Any(file => file.path.StartsWith(@"M:\"))) // 按该影片下符合条件的文件的最大size排序 .OrderBy(movie => movie.files .Where(file => file.path.StartsWith(@"M:\")) .Max(file => file.size)) .ToList();
注意:关于size字段的排序问题
因为你的size字段是Varchar(max)类型,存储的是类似1.54 GB这样的字符串,直接按字符串排序会是字典序(比如100 MB会排在2 GB前面,因为字符串"1"比"2"小)。如果需要按实际文件大小排序,得先把字符串转换成数值,再排序。但EF6无法把自定义的转换函数转换成SQL,所以需要先把数据拉到内存再处理:
// 先写一个解析文件大小字符串的辅助方法 private static double ParseFileSize(string sizeString) { var parts = sizeString.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length != 2 || !double.TryParse(parts[0], out var sizeValue)) return 0; return parts[1].ToLower() switch { "gb" => sizeValue * 1024 * 1024 * 1024, "mb" => sizeValue * 1024 * 1024, "kb" => sizeValue * 1024, "b" => sizeValue, _ => 0 }; } // 然后在LINQ中使用 var sortedMoviesByActualSize = context.movies .Where(movie => movie.files.Any(file => file.path.StartsWith(@"M:\"))) // 先投影出影片和它的最大文件size字符串 .Select(movie => new { Movie = movie, MaxSizeStr = movie.files .Where(file => file.path.StartsWith(@"M:\")) .Max(file => file.size) }) // 拉到内存后再转换排序 .ToList() .OrderBy(item => ParseFileSize(item.MaxSizeStr)) .Select(item => item.Movie) .ToList();
内容的提问来源于stack exchange,提问作者Holly
相关产品推荐
相关产品推荐

