2015-11-12 70 views
0

如果您查詢DbContext的DbSet,則該查詢在DbContext處置之前有效。以下將導致一個例外:實體框架將查詢附加到新的DbContext

IQueryable<Video> allVideos = null; 
using (var context = new MyDbContext()) 
{ 
    allVideos = context.Videos; 
} 
var firstVideo = allVideos.first(); 

顯然,使用DbSet某處存儲在實現的IQueryable返回的對象。

然而,MSDN建議(Link

當使用Web應用程序,使用每個請求的上下文實例。

當然,我可以使用ToList()並返回結果作爲對象列表,但這是相當不可取的,因爲我不知道查詢的原因。

例如:假設我的數據庫有一個收集國家,這些國家的城市有街道,有街道,有房屋,有家庭,有名字的人。

如果有人要求IQueryable,那可能是他想要搜索居住在英國倫敦唐寧街10號的最老人的姓名。

如果我用ToList()返回了序列,那麼所有的城市,街道,房屋,人等等都會被返回,如果他只需要這個人的名字就太浪費了。這是關於延遲執行Linq的好處。

所以我不能返回ToList(),我必須返回IQueryable。

所以我喜歡做的,是打開一個新的DbContext,並以某種方式告訴它應該使用新的DbContext查詢:

IQueryable<Video> allVideos = null; 
using (var context = new MyDbContext()) 
{ 
    allVideos = context.Videos; 
} 
// do something else 
using (var context = new MyDbContext()) 
{ 
    // here some code to attach the query to the new context 
    var firstVideo = allVideos.first(); 
} 

如何做到這一點?

+0

爲什麼要這麼做,只需在第一個上下文中調用ToList()來強制查詢執行 – 3dd

+0

由於@ 3dd建議只執行查詢。請記住,你的查詢只是一個被上下文保留的表達式。它被執行或丟棄。儘管可以保存表達式並稍後執行,但在這種情況下實際上並不需要。 –

回答

0

當地的上師碰巧經過。他向我解釋說,我的設計中的錯誤是我已經使用了DbContext,而我只是編寫查詢。我的界面應該是這樣的,只有在實際物化所請求的對象時才需要DbContext。

的問題是下面的一個簡化版本:

我有一個的DbContext,與一些社會DbSet性能。這些屬性鏡像實際的數據庫。我想隱藏我的抽象數據庫層中的實際數據庫實現,以保護我的數據。我不希望任何人在沒有檢查這些內容是否正確的情況下訪問我的數據庫內容。

這很簡單:只是不要將您的實際DbContext暴露給外部世界,而是暴露隱藏實際使用的DbContext的外觀。該外觀與實際的DbContext進行通信。

大多數函數返回一個IQueryable我需要DbContext來訪問DbSets。這就是爲什麼我想創建一個上下文,構建查詢並處理上下文。但是由於延遲執行,上下文仍然是需要的。

解決方案不是創建自己的上下文,而是讓上下文成爲函數的參數之一。在這種情況下,外部用戶可以調用我的Facade的幾個函數來連接查詢,甚至可以與DbContext上的Linq查詢混合,而無需創建和處理上下文。所以像其他人一樣建議: - 創建上下文 - 調用幾個返回查詢的函數 - 使用ToList()/ ToArray()/ First()/ Count()等執行查詢 - 處理上下文

天冬醯胺的擴展方法

public static IQueryable<Video> GetObsoleteVideos(this MyDbContext context) 
{ 
    // perform several difficult Linq statements on context 
    return ... 
} 

用法:

using (var myContext = new MyDbContext()) 
{ 
    var difficultQuery = myContext.GetObsoleteVideos() 
     .Where(video => ....) 
     .GetBoxingVideos()  // another extension method 
     .Take(10); 
    // query still deferred 
    var result = difficultQuery.ToList() 
} 

這種方式(尤其是如果我創建一個接口),我能夠禁止我DBSets訪問。我甚至可以在內部重組我的Db和DbContext,而無需外部用戶注意任何事情。

-1

有對象上下文中的方法來做到這一點:

var objectContext = ((IObjectContextAdapter)context).ObjectContext; 
objectContext.Detach(entity); 
objectContext.Attach(entity); 

但是,因爲它在從MSDN報價說,你應該使用每個請求的EF上下文的一個實例。這指的是HttpRequest不是針對單個查詢。當你在一個請求中執行操作時,你不應該在你的EF上下文中使用塊,而應該延長它的生命週期。對於新的要求,因此建議不要讓美國跨請求,而是按照協議

  1. 查詢該項目再次重裝(另一個請求可能在此期間已經修改了它)
  2. 進行修改
  3. 保存
+0

這些方法只能附加一個實體,而不是一個表達式,這是OP要查找的 – 3dd