MSTest中使用UseInMemoryDatabase时List<string>需主键的问题排查
问题:使用InMemoryDatabase进行单元测试时,List属性触发“需要定义主键”错误
在使用MSTest编写单元测试、配置UseInMemoryDatabase时,出现错误:实体类型'ListGameWord类的public List<string> WordProgress { get; set; } = new List<string>();属性。添加[NotMapped]特性可消除错误,但会导致对应数据库列消失。
相关代码
Context配置
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<FinalWord>() .HasMany(c => c.Games) .WithOne(e => e.FinalWord); modelBuilder.Entity<Game>() .HasMany(c => c.GameWords) .WithOne(e => e.Game); modelBuilder.Entity<Game>() .HasOne(c => c.FinalWord) .WithMany(e => e.Games); modelBuilder.Entity<Word>() .HasMany(c => c.GameWords) .WithOne(e => e.Word); modelBuilder.Entity<GameWord>() .HasOne(c => c.Game) .WithMany(e => e.GameWords); modelBuilder.Entity<GameWord>() .HasOne(c => c.Word) .WithMany(e => e.GameWords); }
GameWord.cs
public class GameWord { [Key] public int Id { get; set; } public List<string> WordProgress { get; set; } = new List<string>(); [Required] public Word Word { get; set; } [Required] public Game Game { get; set; } public bool Finished { get; set; } = false; }
测试代码
public UnitTest1() { DbContextOptionsBuilder<LingoContext> dbOptions = new DbContextOptionsBuilder<LingoContext>() .UseInMemoryDatabase( Guid.NewGuid().ToString() ); _context = new LingoContext(dbOptions.Options); } [TestMethod] public void GetAllGames() { var repo = new SqlGameRepo(_context); Game game1 = new Game(); Game game2 = new Game(); _context.Game.Add(game1); _context.Game.Add(game2); _context.SaveChanges(); IEnumerable<Game> result = repo.GetAllGames(); Assert.AreEqual(result.Count(), 2); }
错误原因
- InMemory数据库与生产数据库的处理逻辑差异:
生产环境中你大概率使用的是SQL Server这类关系型数据库,EF Core会自动通过值转换器将List<string>序列化为JSON字符串存储在单个列中,或者将其视为拥有类型的集合,不会要求主键。但InMemory数据库不支持这种自动序列化,它会把List<string>当作独立的实体类型处理,而string本身没有主键属性,因此抛出错误。 - 测试上下文未继承生产环境的配置:
你的生产DbContext可能已经配置了针对WordProgress属性的自定义值转换器,但测试代码中创建InMemory上下文时,没有包含该配置,导致InMemory无法正确识别属性的处理方式,进而触发错误。
内容的提问来源于stack exchange,提问作者Bas van der Veen
相关产品推荐
相关产品推荐

