为啥字符串不能像数字一样直接编码

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为啥字符串不能像数字一样直接编码相关的知识,希望对你有一定的参考价值。

参考技术A 对于英文语言的国家是够用了,但是欧洲国家的一些语言会有拼音,这时7个字节就不够用了。因此一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。比如,法语中的é的编码为130(二进制10000010)。这样一来,这些欧洲国家使 用的编码体系,可以表示最多256个符号。但这时问题也出现了:不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码方式,代表的字母却不一样。比如,130在法语编码 中代表了é,在希伯来语编码中却代表了字母Gimel (ג),在俄语编码中又会代表另一个符号。但是不管怎样,所有这些编码方式中,0—127表示的符号是一样的,不一样的只是128—255的这一段。这个问题就直接促使了Unicode编码的产生。

3.Unicode符号集

正如上一节所说,世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。为什么电子邮件常常出现乱码?就是因为发信人和收信人使用的编码方式不一样。而Unicode就是这样一种编码:它包含了世界上所有的符号,并且每一个符号都是独一无二的。比如,U+0639表示阿拉伯字母Ain,U+0041表示英语的大写字母A,U+4E25表示汉字“严”。具体的符号对应表,可以查询unicode.org,或者专门的汉字对应表 。很多人都说Unicode编码,但其实Unicode是一个符号集(世界上所有符号的符号集),而不是一种新的编码方式。

但是正因为Unicode包含了所有的字符,而有些国家的字符用一个字节便可以表示,而有些国家的字符要用多个字节才能表示出来。即产生了两个问题:第一,如果有两个字节的数据,那计算机怎么知道这两个字节是表示一个汉字呢?还是表示两个英文字母呢?第二,因为不同字符需要的存储长度不一样,那么如果Unicode规定用2个字节存储字符,那么英文字符存储时前面1个字节都是0,这就大大浪费了存储空间。

上面两个问题造成的结果是:1)出现了unicode的多种存储方式,也就是说有许多种不同的二进制格式,可以用来表示unicode。2)unicode在很长一段时间内无法推广,直到互联网的出现

为啥我不能像使用列表一样过滤 IQueryable?

【中文标题】为啥我不能像使用列表一样过滤 IQueryable?【英文标题】:Why can't I filter an IQueryable like I can with a List?为什么我不能像使用列表一样过滤 IQueryable? 【发布时间】:2019-09-01 07:21:26 【问题描述】:

我正在稍微重构一个项目,然后又回到了一个我过去从未解决过的问题。我正在尝试对 EF Core db 的查询执行多个过滤器。

过去我曾尝试设置一系列 Where 语句来检查过滤器语句是否为空或通过匹配过滤器。

这在查询中的某处返回了 nullReferenceException。我通过在没有过滤器的情况下运行我的查询然后将过滤器应用到我的列表来解决了这个问题。

我回来创建了一个 WhereIf 扩展,希望它可以解决我的问题,同时让代码更简洁一些,但同样的问题出现了。

我目前尝试在查询上运行四个过滤器,并且它通过了初始过滤器,但如果选择了其他三个过滤器中的任何一个,则查询会出现 nullReferenceException。

如果我从一般查询和第一个过滤器中获取列表,然后将过滤器应用到我的列表,这同样有效。

这是我想做的:

IQueryable<Film> films = _context.Films
    .Include(f => f.Media)
    .Include(f=> f.Audio)
    .Include(f => f.FilmGenres)
        .ThenInclude(fg => fg.Genre)
    .WhereIf(!string.IsNullOrEmpty(vm.SearchValue), f => f.Name.ToLower().Contains(vm.SearchValue.ToLower()))
    .WhereIf(!string.IsNullOrEmpty(vm.MediaFilter), f => f.Media.Name == vm.MediaFilter)
    .WhereIf(!string.IsNullOrEmpty(vm.AudioFilter), f => f.Audio.Name == vm.AudioFilter)
    .WhereIf(!string.IsNullOrEmpty(vm.GenreFilter), f => f.FilmGenres.Any(fg => fg.Genre != null && fg.Genre.Name == vm.GenreFilter));

这里是 WhereIf 方法:

public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> source, bool condition, Expression<Func<TSource, bool>> predicate)
        
            // Performs a Where only when the condition is met

            if (condition)
            
                source = source.Where(predicate);
                return source;
            

            return source;
        

vm.SearchValue 上的过滤器通过正常,当我逐步通过它时,该值是预期的 IQueryable。一旦它命中任何其他过滤器,它就会返回 nullReferenceException(稍后它最终到达 ToList() 时)。如果我在返回之前查看源的值,它会在结果视图中显示它具有空异常。

我已经尝试过每一行(使用电影 = film.Where(...))。我尝试跳过 WhereIf 并只执行 if 语句和标准 Where,所有这些都具有相同的结果。

只有当我创建一个 List 对象,由数据的一般查询填充,然后过滤该 List 对象时,我才能让它工作。

那么,在 EF Core 中过滤 IQueryable 有什么问题?这是不允许的,还是我做错了什么?

更新:所有 Film 对象都具有 Media/Audio/FilmGenre 对象,并且所有内容都已包含在内。并且我已经验证 IQueryable 源中的项目在 WhereIf 方法中的 Where 语句之前具有所有这些项目。

我尝试将每个过滤器语句分别分开,其中包括跳过 WhereIf 方法并同时使用 if 语句。

此外,一次只能选择一个过滤器(目前)。那些没有被选中的结果是条件为假,没有问题。只有在使用有源滤波器时才会打嗝。例如,我将进行仅检查 vm.SearchValue 的初始搜索。这会给我一个电影列表以及过滤和排序的选项。然后,当我选择按音频或媒体等进行过滤时,我遇到了问题。

这是堆栈跟踪:

   at lambda_method(Closure , InternalEntityEntry )
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.SimpleNonNullableDependentKeyValueFactory`1.TryCreateFromCurrentValues(InternalEntityEntry entry, TKey& key)
   at Microsoft.EntityFrameworkCore.Query.Internal.WeakReferenceIdentityMap`1.CreateIncludeKeyComparer(INavigation navigation, InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.IncludeCore(Object entity, INavigation navigation)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.Include(QueryContext queryContext, Object entity, IReadOnlyList`1 navigationPath, IReadOnlyList`1 relatedEntitiesLoaders, Int32 currentNavigationIndex, Boolean queryStateManager)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.Include(QueryContext queryContext, Object entity, IReadOnlyList`1 navigationPath, IReadOnlyList`1 relatedEntitiesLoaders, Boolean queryStateManager)
   at Microsoft.EntityFrameworkCore.Query.Internal.GroupJoinInclude.GroupJoinIncludeContext.Include(Object entity)
   at Microsoft.EntityFrameworkCore.Query.Internal.GroupJoinInclude.GroupJoinIncludeContext.Include(Object entity)
   at Microsoft.EntityFrameworkCore.Query.Internal.GroupJoinInclude.GroupJoinIncludeContext.Include(Object entity)
   at Microsoft.EntityFrameworkCore.Query.Internal.GroupJoinInclude.GroupJoinIncludeContext.Include(Object entity)
   at Microsoft.EntityFrameworkCore.Query.QueryMethodProvider.<_GroupJoin>d__26`4.MoveNext()
   at System.Linq.Enumerable.<SelectManyIterator>d__165`3.MoveNext()
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.<_TrackEntities>d__15`2.MoveNext()
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext()
   at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable`1 source, Int32& length)
   at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable`1 source)
   at System.Linq.SystemCore_EnumerableDebugView`1.get_Items()

以下图片:

    这是在 WhereIf 中的 Where 语句之前通过 SearchValue 过滤器时源的结果视图 在此之后是 Where 语句 这里是通过 AudioFilter - 显示的谓词。 这是执行 AudioFilter 时 Where 语句之前的源 - 与 SearchValue 过滤之后相同 最后,在执行音频过滤时的位置之后

更新:已解决。还有另一项检查涉及导致客户端评估的应用程序用户,该检查已被移动,现在查询按预期工作。

【问题讨论】:

所有电影都肯定有媒体、音频和电影流派关联的实体吗?你包括他们吗?我猜你需要检查例如f =&gt; (f.Media != null) &amp;&amp; (f.Media.Name == vm.MediaFilter)。但我猜这里的 NPE 意味着这并没有被翻译成 SQL 以在数据库上执行,就像你可能希望的那样。 每次添加一个WhereIf。您正在做的事情是导致 EF Core 拆分查询并在 LINQ to Objects 中运行其中的一部分(它在转换为 SQL 方面不如 EF 6),这是您的核心 (npi) 问题。 它的显示方式应该可以工作。一定有什么东西引起了客户的评价。如果您配置 [可选行为:为客户端评估抛出异常](docs.microsoft.com/en-us/ef/core/querying/…) 会发生什么? @Rup 是的,所有这些项目都包括在内(并在调试期间验证它们是否存在)。 @IvanStoev 我想我现在明白了。这可以追溯到你提到的关于客户评估的内容。我忘了在这里添加另一个根据应用​​程序的用户执行的位置。一旦我把它拿出来放在别处,它就起作用了。我仍然不确定所有事情的时间以及为什么基于 SearchValue 的第一个过滤器也没有引起问题,但这似乎是罪魁祸首。这是我没有在这里展示那一点的坏处。感谢您的帮助。 【参考方案1】:

我总是只使用简单的 OR 运算符而不是 WhereIf

 IQueryable<Film> films = _context.Films
    .Include(x => x.Media)
    .Include(x => x.Audio)
    .Include(x => x.FilmGenres)
    .ThenInclude(g => g.Genre)
                .Where(f => string.IsNullOrEmpty(vm.SearchValue) || f.Name.ToLower().Contains(vm.SearchValue.ToLower()))
                .Where(f => string.IsNullOrEmpty(vm.MediaFilter) || f.Media.Name == vm.MediaFilter)
                .Where(f => string.IsNullOrEmpty(vm.AudioFilter) || f.Audio.Name == vm.AudioFilter)
                .Where(f => string.IsNullOrEmpty(vm.GenreFilter) || (f.FilmGenres.Any(fg => fg.Genre != null && fg.Genre.Name == vm.GenreFilter)));

【讨论】:

这是我之前(去年)尝试过的方法,但也遇到了同样的问题,采用了同样的修复方法……先获取列表,然后进行过滤。 FilmGenres、Media 和 Audio 是否可能为空?我知道如果使用.net core,默认情况下不启用延迟加载,所以你需要调用include。 不,他们有价值观。我可以尝试缩小我的 searchValue,使其对象数量非常少,并手动验证每个对象。 我刚刚验证了在应用 AudioFilter 之前存在的对象确实填充了所有必要的值。 啊,好吧...不确定发生了什么然后获得空引用。【参考方案2】:

这个答案是即兴的,是我的一些猜测,所以如果没有帮助,我深表歉意。

无论如何,有几件事对我来说很突出。

首先,您的 WhereIf() 函数 - 它并没有完全实现 Where() 的功能。 Where() 获取一个源并返回第二个源,其中记录集被筛选掉。值得注意的是,它根本不会更改原始数据源。好吧,您的 WhereIf() 正在尝试这样做 - 它正在更改传递给函数的“源”变量。我做了一些谷歌搜索,IQueryable doesn't 看起来是不可变的,这意味着它可以在不创建新类实例的情况下进行更改,所以我不确定这行代码没有搞砸为它的建筑打下基础:

source = source.Where(predicate);

...它会解释你得到的结果。第一个条件为真的 'WhereIf' 有效,但下一个无效 - 因为第一个与它正在处理的基础对象搞乱了。至少,您应该将其更改为“return source.Where(predicate)”,只是为了代码清晰(因为您现有的代码看起来像是 试图 更改它。)

其次,您是否尝试过拆分声明?我的意思是,像这样:

var results = SomeLinq.SomeStatement(a => something(a))
        .Where(b => b == something)
        .Where(c => c == something)

...与以下内容相同:

var mainQueryable = SomeLinq.SomeStatement(a => something(a));
var filtered = mainQueryable.Where(b => b == something);
var results = filtered.Where(c => c == something);

这反过来又可以让您为 LINQ 简化图片:

IQueryable<Film> films = _context.Films
    .Include(f => f.Media)
    .Include(f=> f.Audio)
    .Include(f => f.FilmGenres)
    .ThenInclude(fg => fg.Genre);
if (!string.IsNullOrEmpty(vm.SearchValue)) films = films.Where(f => f.Equals(vm.SearchValue, StringComparison.OrdinalIgnoreCase);
if (!string.IsNullOrEmpty(vm.MediaFilter)) films = films.Where(f => f.Media.Name == vm.MediaFilter);
// etc...

...所以最后的 LINQ 语句没有多余的 WHERE 子句,这些子句实际上不会过滤任何内容。

无论如何,希望这些能有所帮助。

【讨论】:

我实际上已经尝试了所有这些(除了为每次分离使用不同的变量)。 WhereIf 最初确实返回了 source.Where(predicate),但我添加了另一行进行调试,以便我可以看到返回的内容。还需要注意的是,在我使用 WhereIf 之前,使用 .Where(f => string.IsNullOrEmpty(vm.MediaFilter) || f.Media.Name == vm.MediaFilter) 具有相同的结果。 实际上,认为分配给source 是一个问题表明对C# 的工作原理缺乏了解。 source 是一个对象引用,重新分配它以指向不同的对象对原始对象没有任何作用。请参阅Where 的源代码,了解(功能上)相同的内容。

以上是关于为啥字符串不能像数字一样直接编码的主要内容,如果未能解决你的问题,请参考以下文章

为啥TSQL把“sofia”和“sofia”一样对待?这是啥字符串编码?

为啥某些文件的组显示数字(看起来像 ID),而不是字母字符串?

字符串类型

为啥我不能删除字符串的数字字符?

在数字信道中传送数字信号时为啥要编码?

为啥MYSQL要设定用UTF8MB4编码UTF8MB4