簡體   English   中英

如何在EntityFramework 4.1中共享沒有CodeFirst的dbContext?

[英]How do I share dbContext without CodeFirst in EntityFramework 4.1?

長時間潛伏,第一次海報。

我在這里找到了很多關於如何使用CodeFirst在存儲庫之間共享dbContext的東西,但我似乎無法將它與我正在處理的項目聯系起來,它不使用代碼或依賴注入。

首先,關於項目的一點背景,以確保我正在以正確的方式接近這一點。 我進入這個項目,他們首先使用EF4和DB。 我不是EF的專家,但我現在已經摸索了幾個不同的項目。

我不得不實施幾個不同的要求,迫使我介入他們的“服務”級別和數據庫。 換句話說,他們的對象直接調用EF db對象,如

using (var db = new MYDB()){
  var bar = db.Foo
   .Include("Transactions")
   .Include("blah")
   .Where(...);

  //do stuff

  db.SaveChanges();
}

我必須做的一件事就是跟蹤所有變化的字段,所以我抽出了一個級別,現在我們有了

FooObject bar = GetFooObject(...);
bar.Title = "asdfasdf";
//do stuff to bar
bar.Save();

它將所有字段包裝到屬性中,以便我可以注銷任何更改。 在bar.save中,我打開一個db上下文,獲取現有的Foo或創建一個新的,分配所有值,然后調用db.SaveChanges。

事實證明,他們也會根據交易和blah做很多子查詢。 所以,當他們做類似的事情

var bar = GetFooObject(...);

var t = new Transaction();
//do stuff to t
...
bar.Transactions.Add(t);
bar.Save();

我遇到各種上下文錯誤,說dbcontext不再可用等等。我完全理解。 我不知道的是如何解決它。 我已經看到很多關於在使用之前創建dbContext然后將其傳入的內容,但我似乎無法找到正確的方法來實現它,因此它將適用於我的代碼。

我最近的嘗試是基於幾個關於如何將DBContext轉換為ObjectContext的例子(這反過來基於我發現的所有關於共享連接引用ObjectContext而不是DBContext的連接的例子)如下所示:

using (var db = ((IObjectContextAdapter)(new FooDB())).ObjectContext)
  {
using (var context = new DbContext(db, false))
{
var bar = FooObject.GetFooObject(fooId);
Result r = bar.ProcTrans(amount,
                        transDate,
                            db.TransactionTypes
                              .Include(tt => tt.Description)
                              .SingleOrDefault(tt => tt.TypeID == transactionTypeId),
                            employeeId,
                            comment);

但是使用這段代碼我得到一個錯誤,我沒有為TransactionTypes定義。 它無法識別我的任何數據庫對象。

如何創建一個DBContext並將其傳遞給我的FooObject,以便我可以保持它對相關的更新? 我甚至不知道我是否正確地提出這個問題。 如何在不重新編碼整個事物的情況下彌合這一差距?

編輯

以下是自打開此問題以來我發現的一些事情。 也許其中一個會做到這一點。

嗯,這個發現肯定更像是重新編碼整個事情,但我在尋找關於“做變更跟蹤”與觸發器響應的鏈接時發現了這一點。

poco在實體框架第3部分:用poco改變跟蹤

我剛剛發現這個如何在asp.net中的各種模型庫中共享數據上下文,這可能是一種簡單的方法來處理它。

我會留下對象上下文的東西。

我在MVC應用程序中實現共享DBContext的方式如下:

public class BaseRepository
{
    public static MyAppContext GetDataContext()
    {
        string ocKey = "ocm_" + HttpContext.Current.GetHashCode().ToString("x");

        if (!HttpContext.Current.Items.Contains(ocKey))
            HttpContext.Current.Items.Add(ocKey, new MyAppContext());

        return HttpContext.Current.Items[ocKey] as MyAppContext;
    }
}

然后每當我需要進行數據庫操作時,我都可以調用:

BaseRepository.GetDataContext().YourObjects.Where(x => ...);
....
BaseRepository.GetDataContext().SaveChanges();

只要您仍處於相同的HTTP上下文中,您將共享相同的數據庫上下文。 不完全確定這會消除您所獲得的錯誤,但它至少是一種分享您的上下文的方式。

對我來說,答案與我發布的一個鏈接有關。

如何在asp.net中的各種模型存儲庫之間共享數據上下文

當我看到這些類型的注射答案時,讓我失望的是語法上它們對我不起作用。 我沒有DataContext,也沒有任何Repository模型,但我決定在概念上嘗試並在各處傳遞Context。

基本上,我傳遞了與Object構造函數或創建新對象的任何工廠方法的連接,並將其存儲在局部變量中,就像這樣排序。

public class Foo{
    private MyDB _db;
    private Foo _foo;

    public FooObject(MyDB dbContext)
    {
        _db = dbContext;
    }

    public static FooObject GetFooObject(int FooID, MyDB db){
        bool closeFlag = false;

        //if null was passed in, then we will create our own connection and manage it
        if (db == null)
        {
            _db = new MyDB();
            closeFlag = true;
        } else {
            //otherwise, we set our local variable
            _db = db;
        }

        //from now on, all queries are done using the local variable
        var _f = _db.Foos
            .Include("x")
            .Include("y")
            .Include("z")
            .SingleOrDefault(f => f.FooID == FooID);

        var fo = FooObjectFromFoo(_f, db);

        if (closeFlag)
            db.Dispose();

        return fo;
    }

    // This copies all of the values from Foo and puts the into a FooObject
    public static FooObject FooObjectFromFoo(Foo f, MyDB dbContext){
        if (l == null)
            return null;

        // note that we pass the dbContext to the constuctor
        FooObject _f = new FooObject(dbContext){
            _foo = f,
            ...
            //note x, y, and z are the other EF "table references".  I'm not sure what you technically call them.
            x = f.x,
            y = f.y,
            z = f.z
        };

        return _f;
    }


    //we call this to save the changes when we're done
    public bool Save(){
        bool close = false; 
        bool retval = true;

        MyDB db = _db;

        //remember we set _db in the constructor            
        if (db == null) {
            db = new MyDB();
            close = true;
        }

        try
        {
            // a reference to this row should have been saved in _foo if we loaded it from the db.
            // take a look at FooObjectFromFoo
            if (_foo == null)
            {
                _foo = db.Foos.SingleOrDefault(x => x.FooID == _FooID);
            }
            if (_foo == null)
            {
                _foo = new Foo();
            }
            //copy all my object values back to the EF Object
            _foo.blah = blah;
            _foo.x = x;
            _foo.y = y;
            try
            {
                //save the new one.
                db.SaveChanges();

            }
            catch (DbEntityValidationException dbEx)
            {
                TransactionResult.AddErrors(dbEx);
                retval = false;
            }
        }
        catch { throw new Exception("Something went wrong here.");}
        finally { if (close) db.Dispose(); } //if we created this connection then let's close it up.
    }
}

現在在我的方法中,我總是使用本地_db連接。 在我的FooObject之外,我們有一個FooService,它是從所有控制器調用的。 因此,當實例化FooService時,我使用下面的類創建數據庫連接。 如果我理解正確,這應該給我一個在我的服務請求期間存在的上下文,在我的情況下,相當可靠地模仿請求。

namespace My.Domain
{
  public class MyDataContext : IDisposable  {
    private MyDB _context;
    private bool _ownContext;

    public MyDataContext(){
        _context = new MyDB();
        _ownContext = true;
    }

    public MyDataContext(MyDB db)
    {
        _context = db;
        _ownContext = false;
    }

    public MyDB Context
    {
        get { if (_context == null) { _context = new MyDB(); _ownContext = true; } return _context; }
        set { _context = value; }
    }

    public bool OwnContext
    {
        get { return _ownContext; }
        set { _ownContext = value; }
    }

    public void Dispose()
    {
        if (_context != null && _ownContext)
            _context.Dispose();
    }
  }
}

在FooService中我做這樣的事情。

    private MyDb db;

    public FooService (){
        var _db = new MyDataContext();
        db = _db.Context;
    }

    public Result ProcessTransaction(int FooId, string comment)
    {
        var foo = FooObject.GetFooObject(FooId,db);

        Result r = foo.ProcessTransaction(comment);

        if (r.Success)
            foo.Save();

        return r;
    }

我認為這樣做“正確”我應該只在關閉上下文時保存更改...但我已經在我的FooObject上有一個Save方法,所以我只是在那里調用db.SaveChanges。

我知道有很多方法可以改善這一點,我相信隨着時間的推移我會實施其中的一些,但就目前而言,這就是訣竅。 這就是我解決所有“上下文不再可用”的問題,而這個對象來自不同的上下文錯誤。

在查看其他人的例子時,讓我感到震驚的是他們都在使用CodeFirst和某種依賴注入。 他們通常使用Repository模式,但我們沒有。 但事實證明,我只是必須實施我自己的黑客連接注入的本地化版本! :)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM