首页 > 解决方案 > 我可以使用 EF Core 5 InMemory 数据库进行集成测试吗

问题描述

我正在从 net core 3.1 迁移到 net 5(EF Core 3 也迁移到 EF Core 5)。我们正在使用 EF Core 3 InMemory 数据库进行集成测试。迁移测试不再通过并且查询抛出错误后:

System.InvalidOperationException:LINQ 表达式 'ShapedQueryExpression:QueryExpression:InMemoryQueryExpression:ServerQueryExpression:InMemoryTableExpression:实体:RatingExclusionProduct .Where(valueBuffer => IsFalse(ValueBufferTryReadValue(valueBuffer,0,属性:RatingExclusion.Id(UUId)必需 PK AfterSave:Throw)。 Equals(null)) && object.Equals( objA: ExpressionExtensions.ValueBufferTryReadValue( valueBuffer: valueBuffer, index: 0, property: Property: RatingExclusion.Id (UUId) 必需 PK AfterSave:Throw), objB: ExpressionExtensions.ValueBufferTryReadValue( valueBuffer: valueBuffer ,索引:0,属性:属性:RatingExclusionProduct.ExclusionId (UUId) 必需 PK FK AfterSave:Throw)) ProjectionMapping:成员:EmptyProjectionMember 投影:EntityProjectionExpression:属性:RatingExclusionProduct。ExclusionId (UUId) 必需 PK FK AfterSave:Throw -> ExpressionExtensions.ValueBufferTryReadValue( valueBuffer: valueBuffer, index: 0, property: Property: RatingExclusionProduct.ExclusionId (UUId) 必需 PK FK AfterSave:Throw) 属性: RatingExclusionProduct.ProductId (UUId) 必需PK FK 索引 AfterSave:Throw -> ExpressionExtensions.ValueBufferTryReadValue( valueBuffer: valueBuffer, index: 1, property: Property: RatingExclusionProduct.ProductId (UUId) 必需的 PK FK 索引 AfterSave:Throw) ,ValueBufferTryReadValue(valueBuffer: valueBuffer, index: 1, property: Property: RatingExclusionProduct.ProductId (UUId) Required PK FK Index AfterSave:Throw) ,ValueBufferTryReadValue(valueBuffer: valueBuffer, index: 1, property: Property: RatingExclusionProduct.ProductId (UUId) Required PK FK Index AfterSave:Throw) ,

ShaperExpression: EntityShaperExpression: 
        EntityType: RatingExclusionProduct
        ValueBufferExpression: 
            ProjectionBindingExpression: EmptyProjectionMember
        IsNullable: False

.AsQueryable()
.LeftJoin(
    inner: DbSet<ControlProduct>(), 
    outerKeySelector: o0 => EF.Property<UUId>(o0, "ProductId"), 
    innerKeySelector: c => EF.Property<UUId>(c, "Id"), 
    resultSelector: (o, i) => new TransparentIdentifier<RatingExclusionProduct, ControlProduct>(
        Outer = o, 
        Inner = i
    ))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly

通过插入对“AsEnumerable”、“AsAsyncEnumerable”、“ToList”或“ToListAsync”的调用

我们能否以某种方式解决这个问题,或者我们需要切换到另一种模拟数据库的方法?据我所知,发生了重大变化:

https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-5.0/break-changes#no-client-methods

我的问题与它有关吗?我在网上搜索过,有些人建议使用真实数据库进行测试,但我担心这会是一个非常慢的解决方案,而且我们有多个使用单个数据库的上下文,因此很难在测试开始时创建数据库。有些人建议创建上下文聚合(包含所有实体的单个上下文仅用于创建数据库),但我不知道如何实现它。我认为我的问题看起来更像是后续问题的组合,但我对这个话题有点迷茫。非常感谢您的关注。

更新: UUId 是自定义类型,用作我们所有表的 PK。为了解决它,我们使用:

    services
        .AddDbContext<RatingsContext>(opt =>
            opt.AddRelationalTypeMappingSourcePlugin<UUIdTypeMapperPlugin>()
                .UseMySql(connectionString, mso => mso
                    .ServerVersion(new Version(5, 7, 29), ServerType.MySql)
                    .EnableRetryOnFailure()
                )
        );

其中 UUIdTypeMapperPlugin:

public class UUIdTypeMapperPlugin : ITypeMappingSourcePlugin, IRelationalTypeMappingSourcePlugin
{
    public CoreTypeMapping FindMapping(in TypeMappingInfo mappingInfo)
    {
        return mappingInfo.ClrType == typeof(UUId) ? new UUIdTypeMapper() : null;
    }

    public RelationalTypeMapping FindMapping(in RelationalTypeMappingInfo mappingInfo)
    {
        return mappingInfo.ClrType == typeof(UUId) ? new UUIdTypeMapper() : null;
    }
}

和 UUIdTypeMapper:

public class UUIdTypeMapper : RelationalTypeMapping
{
    private static readonly ValueConverter<UUId, byte[]> _converter
        = new ValueConverter<UUId, byte[]>(uuid => uuid.ToByteArray(),
            byteArray => new UUId(byteArray));

    protected UUIdTypeMapper(RelationalTypeMappingParameters parameters) : base(parameters)
    {
    }

    public UUIdTypeMapper() : base(new RelationalTypeMappingParameters(
        new CoreTypeMappingParameters(typeof(UUId), _converter), "binary(16)")
    )
    {
    }

    protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters parameters)
    {
        return new UUIdTypeMapper(parameters);
    }

    public override string GenerateSqlLiteral(object value)
    {
        return $"0x{value}";
    }
}

标签: asp.netentity-framework-coreef-core-3.1ef-core-5.0

解决方案


经过广泛的研究,我发现 EF Core GitHub 上有一个与我的问题相关的未决问题,这是一个错误。

https://github.com/dotnet/efcore/issues/24318

我认为我们的团队应该转向在真实数据库上进行集成测试。有一个有用的链接: https ://medium.com/nerd-for-tech/run-ef-core-integration-tests-in-a-repeatable-and-isolated-way-using-a-public- docker-image-with-a-e912a89c7bf4


推荐阅读