.NET Core API:在 Linux VM 上运行的 docker 容器上升级到 EF Core 3.1 时,列名称“__roleName_0”无效

问题描述 投票:0回答:1

问题的一些背景:

我们最近从 2.2 升级到 .NET Core 3.1,并且还从 2.2 升级到 EF Core 3.1,并且很少有 API 出现故障或出现一些奇怪的问题,而这些问题是迄今为止才出现的。我需要帮助来理解这些问题以便解决它们。

需要注意的一些观察点:

  1. 如果我将 EF Core 3.1 降级到 2.2,则不会出现此问题
  2. 本地测试API时不会出现该问题,只有部署API时才会出现。
  3. 为了部署,我们在 Linux 虚拟机上使用 docker 容器。我在下面共享了 docker 文件以及其他详细信息。

描述

错误类型:SqlException 错误消息:无效的列名称“__roleName_0”

public async Task<List<UserView>> GetUsersAsync(string roleName, int offset, int? limit)
{
    var query = _dbContext.UserView.AsNoTracking().Where(u => u.UserRole.Any(ur => ur.Role.Name == roleName));

    var userResult = await query.ToListAsync();

    return userResult;
}

正如您在

GetUsersAsync
函数中看到的,它有一个数据库操作:

  1. 通过属于该角色的谓词过滤用户。

这是从我们的日志中生成的用于以下操作的 SQL:

通过属于该角色的谓词过滤用户。

Executed DbCommand (177ms) [Parameters=[@__roleName_0='?' (Size = 4000)]
SELECT <ColumnNames>
FROM 
(
    SELECT <ColumnNames>
    FROM [V_User] AS [v]
    WHERE (EXISTS (
        SELECT 1
        FROM [UserRole] AS [u]
        INNER JOIN [Role] AS [r] ON [u].[RoleId] = [r].[Id]
        WHERE [v].[Id] = [u].[UserProfileId]) AND ([r].[Name] = @__roleName_0)
)

由于某种原因,EF Core 将参数 __roleName_0 视为列,这似乎是问题所在。我们尝试了多种资源,包括阅读 EF Core 3.0/3.1 中引入的重大更改,但无法了解此问题的原因是什么。请帮忙。

其他技术细节:

<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.2">
<PackageReference Include="IdentityServer4.EntityFramework" Version="3.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.1.2" />

Dockerfile:

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1.2 AS base
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
WORKDIR /src
COPY <ProjectName>/<ProjectName>.csproj <ProjectName>/
RUN dotnet restore <ProjectName>/<ProjectName>.csproj
COPY . .
WORKDIR /src/<ProjectName>
RUN dotnet build <ProjectName>.csproj -c Release -r ubuntu.16.04-x64 -f netcoreapp3.1 -o /app

FROM build AS publish
RUN dotnet publish <ProjectName>.csproj -c Release -r ubuntu.16.04-x64 -f netcoreapp3.1 --self-contained -o /app

FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "<ProjectName>.dll"]
c# docker asp.net-core ef-core-3.0 ef-core-3.1
1个回答
0
投票

与 EF Core 2.2 相比,此行为可能与 EF Core 3.1 处理查询转换和参数命名的方式有关。您可以尝试的一种潜在解决方法是在构造查询时显式指定参数类型。以下是包含此更改的 GetUsersAsync 方法的更新版本:

public async Task<List<UserView>> GetUsersAsync(string roleName, int offset, int? limit)
{
    var parameter = new SqlParameter("@roleName", roleName); // Explicitly specify parameter name and type
    var query = _dbContext.UserView.AsNoTracking()
        .FromSqlInterpolated($"SELECT * FROM UserView WHERE EXISTS (SELECT 1 FROM UserRole WHERE UserView.Id = UserRole.UserProfileId AND UserRole.RoleId = Role.Id AND Role.Name = {parameter})")
        .Include(u => u.UserRole);

    var userResult = await query.ToListAsync();

    return userResult;
}

在此,我使用 FromSqlInterpolated 构建 SQL 查询,并使用 SqlParameter 显式指定参数名称和类型。当 EF Core 的查询翻译行为导致意外问题时,此方法有时会有所帮助。

我希望这能起作用。

© www.soinside.com 2019 - 2024. All rights reserved.