在没有键的情况下初始化 DbSet 时出错:无法跟踪“MyEntity”类型的实例,因为它没有主键

ca9*_*3d9 5 c# unit-testing entity-framework xunit

我有一个DbContext没有Dbset钥匙的。它在仅查询表的应用程序中工作。

public class MyDbContext : DbContext, IMyDbContext
{
    public MyDbContext(DbContextOptions<MyDbContext> options) : base(options) { }
    public DbSet<MyEntity> MyEntities { get; set; }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<MyEntity>().HasNoKey(); // No key
        modelBuilder.ApplyConfigurationsFromAssembly(typeof(MyDbContext).Assembly);
    }
}
Run Code Online (Sandbox Code Playgroud)

我在测试项目 (xUnit) 中创建以下测试设置类:

public static class MyDbContextFactory
{
    internal static MyDbContext Create()
    {
        var options = new DbContextOptionsBuilder<MyDbContext>()
            .UseInMemoryDatabase(Guid.NewGuid().ToString())
            .Options;
        var context = new MyDbContext(options);
        context.Database.EnsureCreated();
        context.MyEnities.AddRange(new[] // This line got the error!!!
        {
            new MyEntity { Time = DateTime.Now, Instrument = "R1" },
            new MyEntity { Time = DateTime.Now, Instrument = "R2" },
            new MyEntity { Time = DateTime.Now, Instrument = "R3" },
        });
        context.SaveChanges();
        return context;
    }
}

public class QueryTestFixture : IDisposable
{
    public MyDbContext MyDbContext { get; }
    public IMapper Mapper { get; }

    public QueryTestFixture()
    {
        MyDbContext = MyDbContextFactory.Create();
        var configurationProvider = new MapperConfiguration(cfg =>
        {
            cfg.AddProfile<MappingProfile>();
        });
        Mapper = configurationProvider.CreateMapper();
    }

    public void Dispose()
    {
        // ... omitted ...
    }
}

[CollectionDefinition("QueryTests")]
public class QueryCollection : ICollectionFixture<QueryTestFixture> { }
Run Code Online (Sandbox Code Playgroud)

这是测试代码。

[Collection("QueryTests")]
public class MyTest
{
    private readonly MyDbContext _context;
    private readonly IMapper _mapper;

    public MyTest(QueryTestFixture fixture)
    {
        _context = fixture.MyDbContext;
        _mapper = fixture.Mapper;
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,在实际运行测试之前,运行任何测试方法都会出现以下错误。错误发生在context.MyEnities.AddRange(....上面一行。

信息:
    System.AggregateException:发生一个或多个错误。(无法跟踪“MyEntity”类型的实例,因为它没有主键。只能跟踪具有主键的实体类型。)(以下构造函数参数没有匹配的装置数据:QueryTestFixture 装置)
    ---- System.InvalidOperationException:无法跟踪“MyEntity”类型的实例,因为它没有主键。只能跟踪具有主键的实体类型。
    ---- 以下构造函数参数没有匹配的夹具数据:QueryTestFixture 夹具
  堆栈跟踪:
    ----- 内部堆栈跟踪 #1 (System.InvalidOperationException) -----
    StateManager.GetOrCreateEntry(对象实体)
    DbContext.SetEntityStates(IEnumerable`1 实体,EntityState 实体状态)
    DbContext.AddRange(IEnumerable`1 个实体)
    DbContext.AddRange(Object[] 实体)
    InternalDbSet`1.AddRange(TEntity[] 实体)
    MyDbContextFactory.Create() 第 20 行
    QueryTestFixture.ctor() 第 16 行
    ----- 内部堆栈跟踪 #2 (Xunit.Sdk.TestClassException) -----

Lut*_*lho 4

到目前为止,这是实体框架上的一个未决问题:https://github.com/aspnet/EntityFramework.Docs/issues/898

您无法在没有键的情况下在 DbQuery 或 DbSet 上添加新实体。我建议您跟踪这个问题,现在模拟您的上下文或使用Entity Framework Core Mock来完成此任务。