【问题标题】:Error on initialize a DbSet without key: Unable to track an instance of type 'MyEntity' because it does not have a primary key初始化没有键的 DbSet 时出错:无法跟踪“MyEntity”类型的实例,因为它没有主键
【发布时间】:2019-12-16 19:43:26
【问题描述】:

我有一个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);
    }
}

我在测试项目 (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> { }

这里是测试代码。

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

    public MyTest(QueryTestFixture fixture)
    {
        _context = fixture.MyDbContext;
        _mapper = fixture.Mapper;
    }
}

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

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

【问题讨论】:

  • 你想测试什么?为什么不使用 IMyDbContext 的模拟,而是使用 MyDbContext 的具体实例?
  • 您是否尝试过使用AsNoTracking 进行查询?
  • @ca9163d9 在真实应用程序 DbSet 上是映射视图还是表?
  • @LuttiCoelho,这是一个视图。
  • @PavelAnikhouski,在哪里添加AsNoTracking?我尝试添加它(` context.MyEnities.AsNoTracking();) right before context.MyEnities.AddRange(...)` 但它仍然出现错误。

标签: c# entity-framework unit-testing xunit


【解决方案1】:

到目前为止,这是 Entity Framework 上的一个未解决问题:https://github.com/aspnet/EntityFramework.Docs/issues/898

您不能在没有键的情况下在 DbQuery 或 DbSet 上添加新实体。 我建议您跟踪此问题并暂时模拟您的上下文或使用Entity Framework Core Mock 来完成此操作。

【讨论】:

    【解决方案2】:

    以下解决方案对我有用。

    对于场景 #1 和 #2,您可以将以下行添加到 DbContext 模块的 OnModelCreating 方法:modelBuilder.Entity().HasKey(x => new { x.column_a, x.column_b }); // 使记录唯一所需的列数。

    查询的详细信息在 tis url 上。

    https://stackoverflow.com/questions/3996782/entity-framework-table-without-primary-key#:~:text=EF%20does%20not%20require%20a,I%20believe%20you%20are%20hosed.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-03
      • 1970-01-01
      • 2018-06-20
      • 1970-01-01
      • 1970-01-01
      • 2016-08-19
      • 2022-01-02
      相关资源
      最近更新 更多