首页 > 解决方案 > C# Entity Framework 在同一个数据库中创建两个 DbContext´s

问题描述

我有一个包含上下文的通用 DbContext,当我想在 DB 中保存模型时,我想创建此类的实例并保存对象。在测试中,我断言,第一个 Object 已正确保存,但第二个对象确实抛出异常"No such Table"。为了明确这一点,如果我使用之前未创建的其他模型调用我的控制器,它确实会引发此异常。下面的测试表明了这一点。当我查看实际创建的数据库时,其中只有一个表。

有人可以告诉我有什么问题吗?

这是我的 DbContext:

    public class DbEntryController<TEntity> : DbContext
    where TEntity : class
{
    protected static NLog.Logger Log = LogManager.GetCurrentClassLogger();
    private static object _locker = new();

    public DbSet<TEntity> Context { get; set; }

    private string _tableName;

    public DbEntryController(string tableName, DbContextOptions<DbEntryController<TEntity>> options) 
        : base(options)
    {
        _tableName = tableName;
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<TEntity>().ToTable(_tableName, schema: typeof(TEntity).Name);
    }

    public override int SaveChanges()
    {
        var entries = ChangeTracker
         .Entries()
         .Where(e => e.Entity is BaseEntry 
         && (e.State == EntityState.Added
         || e.State == EntityState.Modified));

        foreach (var entityEntry in entries)
        {
            ((BaseEntry)entityEntry.Entity).LastUpdate = DateTime.Now;

            if (entityEntry.State == EntityState.Added)
            {
                ((BaseEntry)entityEntry.Entity).CreationTime = DateTime.Now;
            }
        }

        Database.EnsureCreated();
        Database.Migrate();

        return base.SaveChanges();
    }

    public bool TryAddReceived<T>(string content, T context)
        where T : TEntity, IReceiveDbEntry
    {
        return this.Save(Direction.Received, content, context);
    }

    public bool TryAddSent<T>(string content, T context)
        where T : TEntity, ISendDbEntry
    {
        return this.Save(Direction.Sent, content, context);
    }
}

这是我创建它的实例的方法:

using var db = DbController.FromDBPath<DbEntryController<MyModel>>((options) => new DbEntryController<MyModel>(nameof(MyModel), options));

这里是 FromDBPath 方法:

        public static TContext FromDBPath<TContext>(Func<DbContextOptions<TContext>, TContext> creator, string dbPath = null)
        where TContext : DbContext
    {
        if (dbPath == null)
            Log.Trace($"No DB Path given. Use: {dbPath = Configuration.Instance.SQLiteDbPath}");

        var builder = new DbContextOptionsBuilder<TContext>();

        try
        {
            Log.Trace("Try use sqlite");
            builder.UseSqlite($"Data Source={Path.GetFullPath(dbPath)}");

            Log.Trace("Try create EventLoggingContext");
            var e = creator(builder.Options);
            e.Database.EnsureCreated();

            Log.Trace("DB Create success");

            return e;
        }
        catch (Exception ex)
        {
            Log.Error("Could not create DB");
            Log.Error(ex);

            return creator(builder.Options);
        }
    }

我在 nunit 框架中编写的测试:

        [Test]
    public void InsertSoapRequest()
    {

        var sequence = new SequenceNumberDbEntry { Next = 2000000000 };

        Assert.True(sequence.SuperFancyCreateXmlMethod(out var xml));

        using (var db = (EventLoggingContext)DbController.FromDBPath<DbEntryController<Event>>((options) => new EventLoggingContext("InOut", options), dbPath))
        {
            Assert.True(db.TryAddEvent(xml, Direction.Received));
            Assert.True(db.TryAddEvent(xml, Direction.Sent));
            
            db.SaveChanges();
        }

        using (var db = DbController.FromDBPath<DbEntryController<MyModel>>((options) => new DbEntryController<MyModel>("SequenceNumbers", options), dbPath))
        {

            db.TryAddReceived(xml, sequence);
            var max = db.SelectMaxTransaktionId();

            Assert.AreEqual(2000000000, max);
        }
    }

例外:

在此处输入图像描述

最后但并非最不重要的是我的模型:

    [Table("SequenceNumbers", Schema = nameof(MyModel))]
public class MyModel : BaseEntry, ISendDbEntry, IReceiveDbEntry
{
    public uint Next { get; set; }
    public uint Previos { get; set; }
    public DateTime ReceiveTime { get; set; }
    public DateTime SendTime { get; set; }
}

标签: c#databasesqliteentity-frameworkentity-framework-core

解决方案


推荐阅读