Entity Framework Core - PostgreSQL中将复杂类型映射为jsonb列,但是在InMemory提供程序中映射失败

4

以下是具有复杂属性的类型:

[Table("contact")]
public class Contact
{
    [Key]
    [Column("id")]
    public int Id { get; set; }

    [Column("details", TypeName = "jsonb")]
    public Details Details { get; set; }

    ... 
}
    [ComplexType]
    public class Details
    {
        [JsonProperty("firstName")]
        public string FirstName { get; set; }

        [JsonProperty("middleName")]
        public string MiddleName { get; set; }

        [JsonProperty("lastName")]
        public string LastName { get; set; }
    }

对于pgsql提供程序来说,这很好用:

services.AddDbContextPool<ProfileDbContext>((sp, options) =>
            {
                options.UseNpgsql(connStr,
                    x =>
                    {
                        x.EnableRetryOnFailure();
                        x.CommandTimeout(120);
                    });
            });

但是在将它替换为内存提供程序时,在 TestsStartup 中

services.AddDbContextPool<ProfileDbContext>(options =>
            {
                ServiceProvider sp = new ServiceCollection()
                    .AddEntityFrameworkInMemoryDatabase()
                    .BuildServiceProvider();

                options.UseInMemoryDatabase("Profile", _databaseRoot);
                options.UseInternalServiceProvider(sp);
            });

出现错误:

实体类型“Details”需要定义主键。如果您打算使用无键实体类型,请调用“HasNoKey()”。

如果我通过Fluent配置指定关联OwnsOne,则在InMemory中可以正常工作,但在使用pgsql提供程序启动时失败。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
   modelBuilder.Entity<Contact>(c => c.OwnsOne(e => e.Details));
}

我猜这是因为jsonb字段类型不被内存提供程序支持,是吗?

那么集成测试该怎么办呢?

我们在所有测试中都使用了内存提供程序,但这个jsonb功能似乎破坏了与内存提供程序的技巧。


我认为你已经回答了自己的问题。 - Gert Arnold
2个回答

3

对于测试而言,InMemory是一个非常有限的解决方案,因为它无法执行真实数据库可以执行的许多操作——事务、原始SQL以及在这种情况下的jsonb类型。

对于完整的集成测试,通常建议使用实际生产数据库,从而获得最佳的测试保真度——EF Core文档提供了详细信息。否则,对于单元测试,您可以拥有存储库抽象并进行模拟,这样您就不需要使用EF Core。


2
在你的 dbcontext 模型中:
 public class PostgreSqlDbContextMock : PostgreDbContext
    {
        public PostgreSqlDbContextMock(DbContextOptions<PostgreSqlDbContextMock> options) : base(options)
        {
        }
        
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            base.OnConfiguring(optionsBuilder);
            optionsBuilder.UseInMemoryDatabase(Guid.NewGuid().ToString());
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<EntityWithJsonbProperty>().Property(x => x.SessionData).HasConversion(
                v => JsonConvert.SerializeObject(v, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }),
                v => JsonConvert.DeserializeObject<YouJsonbProperty>(v, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }));
        }
    }

目前您的回答写得不清楚。请编辑并添加更多细节,以帮助其他人理解如何回答问题。您可以在帮助中心找到有关如何编写良好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接