我可以使用 EF Core 5 InMemory 数据库进行集成测试吗
Can I Use EF Core 5 InMemory Database For Integration Testing
我正在努力从 net core 3.1 迁移到 net 5(EF Core 3 到 EF Core 5)。我们使用 EF Core 3 InMemory 数据库进行集成测试。迁移测试不再通过且查询抛出错误后:
System.InvalidOperationException: The LINQ expression
'ShapedQueryExpression:
QueryExpression:
InMemoryQueryExpression:
ServerQueryExpression:
InMemoryTableExpression: Entity: RatingExclusionProduct
.Where(valueBuffer => IsFalse(ValueBufferTryReadValue(valueBuffer, 0, Property:
RatingExclusion.Id (UUId) Required PK AfterSave:Throw).Equals(null))
&& object.Equals(
objA: ExpressionExtensions.ValueBufferTryReadValue(
valueBuffer: valueBuffer,
index: 0,
property: Property: RatingExclusion.Id (UUId) Required PK AfterSave:Throw),
objB: ExpressionExtensions.ValueBufferTryReadValue(
valueBuffer: valueBuffer,
index: 0,
property: Property: RatingExclusionProduct.ExclusionId (UUId) Required PK FK
AfterSave:Throw)))
ProjectionMapping:
Member: EmptyProjectionMember Projection: EntityProjectionExpression:
Property: RatingExclusionProduct.ExclusionId (UUId) Required PK FK AfterSave:Throw ->
ExpressionExtensions.ValueBufferTryReadValue(
valueBuffer: valueBuffer,
index: 0,
property: Property: RatingExclusionProduct.ExclusionId (UUId) Required PK FK
AfterSave:Throw)
Property: RatingExclusionProduct.ProductId (UUId) Required PK FK Index AfterSave:Throw ->
ExpressionExtensions.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
by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList',
or 'ToListAsync'
我们能否以某种方式解决这个问题,或者我们需要切换到另一种模拟数据库的方法?据我所知,有重大变化:
https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-5.0/breaking-changes#no-client-methods
我的问题与它有关吗?我在网上搜索过,有些人建议使用真实数据库进行测试,但我担心这会是一个非常慢的解决方案,而且我们有多个上下文使用单个数据库,因此很难在测试开始时创建数据库。有些人建议创建上下文聚合(仅包含用于数据库创建目的的所有实体的单个上下文),但我不知道如何实现它。我认为我的问题看起来更像是结果问题的组合,但我对这个话题有点迷茫。非常感谢您的关注。
更新:
UUId 是自定义类型,用作我们所有表的主键。
为了解决它,我们使用:
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}";
}
}
经过广泛研究后,我发现 EF Core GitHub 上有一个与我的问题相关的未决问题,它是一个错误。
https://github.com/dotnet/efcore/issues/24318
我认为我们的团队应该转向在真实数据库上进行集成测试。有一个有用的link:
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
我正在努力从 net core 3.1 迁移到 net 5(EF Core 3 到 EF Core 5)。我们使用 EF Core 3 InMemory 数据库进行集成测试。迁移测试不再通过且查询抛出错误后:
System.InvalidOperationException: The LINQ expression 'ShapedQueryExpression: QueryExpression: InMemoryQueryExpression: ServerQueryExpression: InMemoryTableExpression: Entity: RatingExclusionProduct .Where(valueBuffer => IsFalse(ValueBufferTryReadValue(valueBuffer, 0, Property: RatingExclusion.Id (UUId) Required PK AfterSave:Throw).Equals(null)) && object.Equals( objA: ExpressionExtensions.ValueBufferTryReadValue( valueBuffer: valueBuffer, index: 0, property: Property: RatingExclusion.Id (UUId) Required PK AfterSave:Throw), objB: ExpressionExtensions.ValueBufferTryReadValue( valueBuffer: valueBuffer, index: 0, property: Property: RatingExclusionProduct.ExclusionId (UUId) Required PK FK AfterSave:Throw))) ProjectionMapping: Member: EmptyProjectionMember Projection: EntityProjectionExpression: Property: RatingExclusionProduct.ExclusionId (UUId) Required PK FK AfterSave:Throw -> ExpressionExtensions.ValueBufferTryReadValue( valueBuffer: valueBuffer, index: 0, property: Property: RatingExclusionProduct.ExclusionId (UUId) Required PK FK AfterSave:Throw) Property: RatingExclusionProduct.ProductId (UUId) Required PK FK Index AfterSave:Throw -> ExpressionExtensions.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
by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'
我们能否以某种方式解决这个问题,或者我们需要切换到另一种模拟数据库的方法?据我所知,有重大变化:
https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-5.0/breaking-changes#no-client-methods
我的问题与它有关吗?我在网上搜索过,有些人建议使用真实数据库进行测试,但我担心这会是一个非常慢的解决方案,而且我们有多个上下文使用单个数据库,因此很难在测试开始时创建数据库。有些人建议创建上下文聚合(仅包含用于数据库创建目的的所有实体的单个上下文),但我不知道如何实现它。我认为我的问题看起来更像是结果问题的组合,但我对这个话题有点迷茫。非常感谢您的关注。
更新: UUId 是自定义类型,用作我们所有表的主键。 为了解决它,我们使用:
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}";
}
}
经过广泛研究后,我发现 EF Core GitHub 上有一个与我的问题相关的未决问题,它是一个错误。
https://github.com/dotnet/efcore/issues/24318
我认为我们的团队应该转向在真实数据库上进行集成测试。有一个有用的link: 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