Я не понимаю, почему я не получаю никаких результатов от метода ниже:
protected async Task<TEntity> GetAsync(string friendlyName, Func<IQueryable<TEntity>, IQueryable<TEntity>> includes = null)
{
return await (includes == null
? GetAllCurrent()
: includes(GetAllCurrent()))
.SingleOrDefaultAsync(e => e.FriendlyName == friendlyName);
}
При проверке с помощью SQL Server Profiler я вижу, что выполняется следующее:
exec sp_executesql N'SELECT [entity].[Id], [entity].[AgroRangeMultiplier], [entity].[AttackRange], [entity].[CastAreaId], [entity].[ClassId], [entity].[CreatedOnUtc], [entity].[CurrentId], [entity].[EffectId], [entity].[EnergyCost], [entity].[FriendlyName], [entity].[MaxVelocity], [entity].[PreAttackDelay], [entity].[Range], [entity].[RarityId], [entity].[StatusEffectId], [entity].[ThemeId], [entity].[TimeInBetweenAttacksSec], [entity].[TimeToReachMaxVelocitySec], [entity].[UnlockedAtRank], [entity].[UpdatedOnUtc], [entity].[VersionComment], [entity].[Id], [entity].[Name_De], [entity].[Name_En], [entity].[Name_Es], [entity].[Name_Fr], [entity].[Name_It], [entity].[Name_Ja], [entity].[Name_Ko], [entity].[Name_Pl], [entity].[Name_Pt], [entity].[Name_Ru], [entity].[Name_Tr], [entity].[Name_Zh], [entity].[Id], [entity].[DescriptionOnCard_De], [entity].[DescriptionOnCard_En], [entity].[DescriptionOnCard_Es], [entity].[DescriptionOnCard_Fr], [entity].[DescriptionOnCard_It], [entity].[DescriptionOnCard_Ja], [entity].[DescriptionOnCard_Ko],
[entity].[DescriptionOnCard_Pl], [entity].[DescriptionOnCard_Pt], [entity].[DescriptionOnCard_Ru], [entity].[DescriptionOnCard_Tr], [entity].[DescriptionOnCard_Zh], [entity].[Id], [entity].[DescriptionMarkdown_De],
[entity].[DescriptionMarkdown_En], [entity].[DescriptionMarkdown_Es], [entity].[DescriptionMarkdown_Fr], [entity].[DescriptionMarkdown_It], [entity].[DescriptionMarkdown_Ja], [entity].[DescriptionMarkdown_Ko],
[entity].[DescriptionMarkdown_Pl], [entity].[DescriptionMarkdown_Pt], [entity].[DescriptionMarkdown_Ru], [entity].[DescriptionMarkdown_Tr], [entity].[DescriptionMarkdown_Zh], [entity.CastArea].[Id],
[entity.CastArea].[CreatedOnUtc], [entity.CastArea].[CurrentId], [entity.CastArea].[FriendlyName], [entity.CastArea].[UpdatedOnUtc], [entity.CastArea].[VersionComment], [entity.CastArea].[Id], [entity.CastArea].[Name_De],
[entity.CastArea].[Name_En], [entity.CastArea].[Name_Es], [entity.CastArea].[Name_Fr], [entity.CastArea].[Name_It], [entity.CastArea].[Name_Ja], [entity.CastArea].[Name_Ko], [entity.CastArea].[Name_Pl],
[entity.CastArea].[Name_Pt], [entity.CastArea].[Name_Ru], [entity.CastArea].[Name_Tr], [entity.CastArea].[Name_Zh], [entity.StatusEffect].[Id], [entity.StatusEffect].[CreatedOnUtc], [entity.StatusEffect].[CurrentId],
[entity.StatusEffect].[FriendlyName], [entity.StatusEffect].[UpdatedOnUtc], [entity.StatusEffect].[VersionComment], [entity.StatusEffect].[Id], [entity.StatusEffect].[Name_De], [entity.StatusEffect].[Name_En],
[entity.StatusEffect].[Name_Es], [entity.StatusEffect].[Name_Fr], [entity.StatusEffect].[Name_It], [entity.StatusEffect].[Name_Ja], [entity.StatusEffect].[Name_Ko], [entity.StatusEffect].[Name_Pl],
[entity.StatusEffect].[Name_Pt], [entity.StatusEffect].[Name_Ru], [entity.StatusEffect].[Name_Tr], [entity.StatusEffect].[Name_Zh], [entity.Effect].[Id], [entity.Effect].[CreatedOnUtc], [entity.Effect].[CurrentId],
[entity.Effect].[FriendlyName], [entity.Effect].[UpdatedOnUtc], [entity.Effect].[VersionComment], [entity.Effect].[Id], [entity.Effect].[Name_De], [entity.Effect].[Name_En], [entity.Effect].[Name_Es], [entity.Effect].[Name_Fr], [entity.Effect].[Name_It], [entity.Effect].[Name_Ja], [entity.Effect].[Name_Ko], [entity.Effect].[Name_Pl], [entity.Effect].[Name_Pt], [entity.Effect].[Name_Ru], [entity.Effect].[Name_Tr], [entity.Effect].[Name_Zh], [entity.Class].[Id], [entity.Class].[CreatedOnUtc], [entity.Class].[CurrentId], [entity.Class].[FriendlyName], [entity.Class].[UpdatedOnUtc], [entity.Class].[VersionComment], [entity.Class].[Id], [entity.Class].[Name_De], [entity.Class].[Name_En], [entity.Class].[Name_Es], [entity.Class].[Name_Fr], [entity.Class].[Name_It], [entity.Class].[Name_Ja], [entity.Class].[Name_Ko], [entity.Class].[Name_Pl], [entity.Class].[Name_Pt], [entity.Class].[Name_Ru], [entity.Class].[Name_Tr], [entity.Class].[Name_Zh], [entity.Rarity].[Id], [entity.Rarity].[CreatedOnUtc], [entity.Rarity].[CurrentId], [entity.Rarity].[FriendlyName], [entity.Rarity].[UpdatedOnUtc], [entity.Rarity].[VersionComment], [entity.Rarity].[Id], [entity.Rarity].[Name_De], [entity.Rarity].[Name_En], [entity.Rarity].[Name_Es], [entity.Rarity].[Name_Fr], [entity.Rarity].[Name_It],
[entity.Rarity].[Name_Ja], [entity.Rarity].[Name_Ko], [entity.Rarity].[Name_Pl], [entity.Rarity].[Name_Pt], [entity.Rarity].[Name_Ru], [entity.Rarity].[Name_Tr], [entity.Rarity].[Name_Zh], [entity.Theme].[Id], [entity.Theme].[CreatedOnUtc], [entity.Theme].[CurrentId], [entity.Theme].[FriendlyName], [entity.Theme].[UpdatedOnUtc], [entity.Theme].[VersionComment], [entity.Theme].[Id], [entity.Theme].[Name_De], [entity.Theme].[Name_En], [entity.Theme].[Name_Es], [entity.Theme].[Name_Fr], [entity.Theme].[Name_It], [entity.Theme].[Name_Ja], [entity.Theme].[Name_Ko], [entity.Theme].[Name_Pl], [entity.Theme].[Name_Pt], [entity.Theme].[Name_Ru], [entity.Theme].[Name_Tr], [entity.Theme].[Name_Zh]
FROM [Card] AS [entity]
INNER JOIN [CardCastArea] AS [entity.CastArea] ON [entity].[CastAreaId] = [entity.CastArea].[Id]
LEFT JOIN [CardStatusEffect] AS [entity.StatusEffect] ON [entity].[StatusEffectId] = [entity.StatusEffect].[Id]
LEFT JOIN [CardEffect] AS [entity.Effect] ON [entity].[EffectId] = [entity.Effect].[Id]
INNER JOIN [CardClass] AS [entity.Class] ON [entity].[ClassId] = [entity.Class].[Id]
INNER JOIN [Rarity] AS [entity.Rarity] ON [entity].[RarityId] = [entity.Rarity].[Id]
INNER JOIN [CardTheme] AS [entity.Theme] ON [entity].[ThemeId] = [entity.Theme].[Id]
WHERE [entity].[FriendlyName] = @__friendlyName_0
ORDER BY [entity].[Id]',N'@__friendlyName_0 nvarchar(450)',@__friendlyName_0=N'stanofmanymoons'
Обратите внимание, что фильтрация выполняется на уровне базы данных с WHERE [entity].[FriendlyName] = @__friendlyName_0
Если я передам FriendlyName с правильным верблюжьим корпусом, возвращаемое значение будет правильным.
При выполнении оператора sql в SSMS я получаю искомое значение, но оно НЕ возвращается EF:
790992AD-D8CE-4ECB-B552-B4BDA5BCDD75 3.33 0.6 E7CCBCBD-024C-4EF0-9126-4F5E62E83A5F 7C15DABB-FDDC-44B1-AC6A-6DE268A3DF00 2018-11-13 08:21:44.9400000 790992AD-D8CE-4ECB-B552-B4BDA5BCDD75 134DFCC4-5867-47A3-80A4-4D560452538A 4 StanOfManyMoons 0.675 0 0.6 D4A7E01F-C1BB-431C-8687-B4946345DB29 NULL 4AF29C4A-282A-4FB8-8691-9D44398A97F2 0.5 0.1 5 2018-11-13 08:21:44.9400000 Initial creation by seeder 790992AD-D8CE-4ECB-B552-B4BDA5BCDD75 NULL Stan of Many Moons NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 790992AD-D8CE-4ECB-B552-B4BDA5BCDD75 NULL Charged: Casts a fiery blast at all enemies. NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 790992AD-D8CE-4ECB-B552-B4BDA5BCDD75 NULL Stan of many Moons is a 4-cost fighter from the Adventure theme who is available at rank 5 that deals damage to all enemy units on the battlefield with his effect. NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL E7CCBCBD-024C-4EF0-9126-4F5E62E83A5F 2018-11-13 08:21:43.7533333 E7CCBCBD-024C-4EF0-9126-4F5E62E83A5F OwnSide 2018-11-13 08:21:43.7533333 Initial creation by seeder E7CCBCBD-024C-4EF0-9126-4F5E62E83A5F NULL Own Side NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 134DFCC4-5867-47A3-80A4-4D560452538A 2018-11-13 08:21:38.6466667 134DFCC4-5867-47A3-80A4-4D560452538A Charged 2018-11-13 08:21:38.6466667 Initial creation by seeder 134DFCC4-5867-47A3-80A4-4D560452538A NULL Charged NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 7C15DABB-FDDC-44B1-AC6A-6DE268A3DF00 2018-11-13 08:21:37.2100000 7C15DABB-FDDC-44B1-AC6A-6DE268A3DF00 Fighter 2018-11-13 08:21:37.2100000 Initial creation by seeder 7C15DABB-FDDC-44B1-AC6A-6DE268A3DF00 NULL Fighter NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL D4A7E01F-C1BB-431C-8687-B4946345DB29 2018-11-13 08:21:36.9700000 D4A7E01F-C1BB-431C-8687-B4946345DB29 Legendary 2018-11-13 08:21:36.9700000 Initial creation by seeder D4A7E01F-C1BB-431C-8687-B4946345DB29 NULL Legendary NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 4AF29C4A-282A-4FB8-8691-9D44398A97F2 2018-11-13 08:21:41.2266667 4AF29C4A-282A-4FB8-8691-9D44398A97F2 Adventure 2018-11-13 08:21:41.2266667 Initial creation by seeder 4AF29C4A-282A-4FB8-8691-9D44398A97F2 NULL Adventure NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
Если я адаптирую код к:
.SingleOrDefaultAsync(e => string.Equals(e.FriendlyName, friendlyName, StringComparison.InvariantCultureIgnoreCase))
Результат, возвращаемый методом, является правильным, но все объекты загружаются, и SingleOrDefault
выполняется в памяти (чего я абсолютно хочу избежать).
Параметры сортировки БД не чувствительны к регистру (SQL_Latin1_General_CP1_CI_AS).
Теперь к вопросам:
- Как сделать этот запрос нечувствительным к регистру при выполнении фильтрации на уровне базы данных (предложение WHERE)
- Почему мой код не работает? Кажется, сгенерированный SQL-запрос корректен, но EF выполняет дополнительную фильтрацию в памяти, где применяет сравнение с учетом регистра.