如何在不传递上下文的情况下读取添加到DbContext的实体

时间:2014-01-17 14:08:38

标签: c# database entity-framework transactionscope

我目前正在开发一个系统,它的层之间的通信非常复杂,有几个类可以查询数据库,这些类中的每一个都有一个DbContext实例,这些类由一个负责调用的类调用将数据提交到数据库,一个类负责查询数据库中的只读数据。 现在发生的事情是“作家”类必须为其中的每个调用传递此上下文,让我们说:

public class Writer {
    private DbContextClass _context;
    public DbContextClass Context
    {
        get
        {
            if (_context == null)
            {
                _context = new DbContextClass();
            }
            return _context;
        }
        set
        {
            _context = value;
        }
    }

    public void WriteToDatabase() {
        MethodCallA();
        MethodCallB();
        MethodCallC();
        Context.SaveChanges();
    }

    public void MethodCallA() {
        var entityA = (from c in Context.EntitiesA where c.id == 1).FirstOrDefault();
        entityA.FieldA = "changed";
        Context.SaveChanges();
    }

    public void MethodCallB() {
        //very long task here, probably creating a pdf and uploading to another place
        var entityB = new EntitiesB();
        entityB.FieldB = "new";
        Context.AddToEntitiesB(entityB);
    }

    public void MethodCallC() {
        var changedEntityA = (from c in Context.EntitiesA where c.id == 1).FirstOrDefault();
        var newEntityB = (from c in Context.EntitiesB where c.FieldB == "new").FirstOrDefault();
        var newEntityC = new EntitiesC();
        newEntityC.FieldC = newEntityB.FieldB + changedEntityA.FieldA;
        Context.AddToEntitiesC(newEntityC);
    }
}

因此,他们在方法上共享相同上下文的原因是能够执行我在MethodCallC()上所做的事情,他们希望能够在将实体发送到数据库之前将实体插入到上下文中。

我想知道是否可以重构这些方法,因此每个方法都有自己的上下文,并且仍然能够实现相同的结果,换句话说,仍然能够读取尚未发送到的数据数据库呢。

我的第一个想法是删除“Context”属性,并在每个方法内部创建一个新的上下文,唯一的问题是这些操作可能是也可能不是原子的,也就是说,有些方法只是将数据更新为数据库没有担心发生了什么,因此调用了SaveChanges,并且有些方法依赖于对上下文所做的更改,所以我认为这应该在“WriteToDatabase”方法中调用TransactionScope,围绕所有其他方法,推理这背后是我想确保每次调用数据库的时间都尽可能少,因为今天我无法确定数据库连接何时关闭,对吧?

简而言之,TransactionScope将保证在其范围内创建的每个新DbContext都会读取尚未提交到数据库中的数据(在调用SaveChanges之前),以便其他方法可以创建自己的上下文并尽快完成所需的任何关闭连接尽可能? 另一个问题是,由于连接将在某个时刻在事务内部打开,它将保持打开直到事务结束?或者一旦执行查询就会关闭它?

我最大的挑战是能够确保此代码尽可能少地与数据库进行通信。

2 个答案:

答案 0 :(得分:1)

我认为你使用了错误的模式来解决你的问题。您应该查看Repository和UnitOfWork模式,并使用依赖注入来确保在一个工作单元期间在所有组件中使用相同的DbContext。这是starting point

您必须了解模式并根据您的应用进行调整。

答案 1 :(得分:1)

听起来像CQRS类型的设置 - 我猜没有非规范化的读取模型等。

我会看看依赖注入。它可以控制生命范围等。你的代码听起来很难维护 - 绕过上下文永远不是一个好兆头。

这个article讨论会话管理,它等同于EF上下文

您可能希望使用DI查看命令模式和处理程序。像这样article

您可以使用装饰器模式来管理命令的事务范围。