[英]How do you use Moles to mole DbContext from querying the database in EntityFramework 4.1?
[英]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,以便我可以保持它對相關的更新? 我甚至不知道我是否正確地提出這個問題。 如何在不重新編碼整個事物的情況下彌合這一差距?
以下是自打開此問題以來我發現的一些事情。 也許其中一個會做到這一點。
嗯,這個發現肯定更像是重新編碼整個事情,但我在尋找關於“做變更跟蹤”與觸發器響應的鏈接時發現了這一點。
我剛剛發現這個如何在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上下文中,您將共享相同的數據庫上下文。 不完全確定這會消除您所獲得的錯誤,但它至少是一種分享您的上下文的方式。
對我來說,答案與我發布的一個鏈接有關。
當我看到這些類型的注射答案時,讓我失望的是語法上它們對我不起作用。 我沒有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.