通过值转换定义属性的Linq查询

时间:2020-03-30 15:46:48

标签: c# ef-core-3.1

很抱歉,标题令人困惑。

我有一个User实体,该实体存储外部ID的列表。

public class User
{
    public Guid Id { get; set; }

    public string Name { get; set; }

    public int[] ExternalIds { get; set; }
}

我正在使用EF Core value converters将这些值转换为逗号分隔的字符串。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    var valueComparer = new ValueComparer<int[]>(
        (c1, c2) => c1.SequenceEqual(c2),
        c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())),
        c => c.ToArray());

    modelBuilder
        .Entity<User>()
        .Property(user => user.ExternalIds)
        .HasConversion(
            externalIds => string.Join(',', externalIds),
            dbExternalIds => dbExternalIds.Split(',', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray())
        .Metadata
        .SetValueComparer(valueComparer);
}

现在,我在通过ExternalIds查询时遇到问题。 如果运行以下命令,则会返回正确构造的User对象

using (var context = new PersonDbContext())
{
    var allUsers = context.Users.ToList();
}

但是,如果我尝试使用ExternalIds进行查询

第一次尝试是一个简单的查询,如下所示:

var user = 
    context.Users.FirstOrDefault(u => u.ExternalIds.Contains(externalId));

但这不会返回任何结果,这并不奇怪,因为这是生成的SQL

SELECT TOP(1) [u].[Id], [u].[ExternalIds], [u].[Name]
FROM [Users] AS [u]
WHERE CAST(1 AS bit) = CAST(0 AS bit)

我一直在考虑通过EF.Functions进行Like个查询,但由于ExternalIds不是字符串而无法编译

var user = context.Users
    .FirstOrDefault(u =>
        EF.Functions.Like(u.ExternalIds, "%1%"));

通过具有值转换器的属性查询的正确方法是什么?

虽然我不喜欢将值存储为逗号分隔的字符串,但将ExternalIds放入专用表中听起来像是一种过大的杀伤力-它只会有Ids而没有其他内容。

我正在.Net Core 3.1上使用EF Core 3.1。

<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.1.2" />

0 个答案:

没有答案