2011-08-26 51 views
17

我有以下代碼:實體框架4.1:無法從投的DBQuery到的ObjectQuery

public void DeleteAccountsForMonth(int year, int month) 
{ 
    var result = from acm in this._database.AccountsOnMonth 
       where ((acm.Year == year) && (acm.Month == month)) 
       select acm.Id; 
    var query = (ObjectQuery<int>)result; 

    string sql = string.Format(
     "DELETE FROM [AccountsOnMonth] WHERE [AccountsOnMonth].[Id] IN ({0})", 
     query.ToTraceString() 
    ); 

    var parameters = new List<System.Data.SqlClient.SqlParameter>(); 
    foreach (ObjectParameter parameter in query.Parameters) 
    { 
     parameters.Add(new System.Data.SqlClient.SqlParameter { 
      ParameterName = parameter.Name, 
      Value = parameter.Value 
     }); 
    } 

    this._database.Database.ExecuteSqlCommand(sql, parameters.ToArray()); 
} 

基本上,我想要做的是從環境中刪除的大量數據(獲得查詢結果,獲取SQL並執行它)。但是在將result轉換爲ObjectQuery時,我遇到問題。給出的例外是

無法轉換 類型的對象 'System.Data.Entity.Infrastructure.DbQuery 1[System.Int32]' to type 'System.Data.Objects.ObjectQuery 1 [System.Int32]'。

有人可以提供任何提示來解決這個問題嗎?謝謝!

編輯:拉吉斯拉夫第一個解決方案幫我解決了問題,但它happenned有點問題,生成的SQL查詢的SQL參數,即由query.ToString()生成的SQL查詢是這樣的:

DELETE FROM [SncAccountOnMonths] WHERE [SncAccountOnMonths].[Id] IN (
    SELECT [Extent1].[Id] AS [Id] 
    FROM [dbo].[SncAccountOnMonths] AS [Extent1] 
    WHERE ([Extent1].[Year] = @p__linq__0) AND ([Extent1].[Month] = @p__linq__1)) 

問題是變量@p__linq__0@p__linq__1哪裏沒有聲明,所以查詢給出了錯誤「必須聲明標量變量@p_ linq _0」(我確定它會給變量@p__linq__1帶來同樣的錯誤)。爲了「聲明」他們,我需要通過他們作爲ExecuteSqlCommand()的參數。因此,對於最初的回答最終的解決方案是下面的代碼:

public void DeleteAccountsForMonth(int year, int month) 
{ 
    var result = (this._database.AccountsOnMonth 
     .Where(acm => (acm.Year == year) && (acm.Month == month))) 
     .Select(acm => acm.Id); 
    var query = (DbQuery<int>)result; 

    string sql = string.Format(
     "DELETE FROM [AccountsOnMonth] WHERE [AccountsOnMonth].[Id] IN ({0})", 
     query.ToString() 
    ); 

    this._database.Database.ExecuteSqlCommand(sql, 
     new SqlParameter("p__linq__0", year), 
     new SqlParameter("p__linq__1", month) 
    ); 
} 

順便說一句,我認爲始終產生的變量的格式@p__linq__,除非微軟的實體框架團隊在今後的任何EF更新改變它。 ..

回答

22

這是因爲您的_database來自DbContext而您的AccountsOfMonthDbSet<>。在這種情況下,您不能直接使用ObjectQuery,因爲DbSet<>產生的DbQuery<>不能轉換爲ObjectQuery<>

您必須直接使用DbQuery<>

var result = from acm in this._database.AccountsOnMonth 
      where ((acm.Year == year) && (acm.Month == month)) 
      select acm.Id; 
var query = (DbQuery<int>)result; 

string sql = string.Format(
    "DELETE FROM [AccountsOnMonth] WHERE [AccountsOnMonth].[Id] IN ({0})", 
    query.ToString() 
); 

或者你必須先將背景轉換爲ObjectContext創造ObjectSet<>

var objectContext = ((IObjectContextAdapter)_database).ObjectContext; 
var set = objectContext.CreateObjectSet<AccountsOnMonth>(); 
var resut = from acm in set 
      where ((acm.Year == year) && (acm.Month == month)) 
      select acm.Id; 

與第一種方法的問題是,DbQuery不提供Parameters集合 - 僅僅是DbContext API簡化的另一個例子,它使得它更難使用。

+0

感謝您的幫助!檢查編輯我的文章(我添加了最終的解決方案),因爲它發生SQL參數的一個小問題。無論哪種方式,它都解決了! :) – jmpcm

1

在我來說,我真的需要的參數,我發現這個解決辦法:

var query = (DbQuery<int>)result; 

FieldInfo internalQueryField = query.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Where(f => f.Name.Equals("_internalQuery")).FirstOrDefault(); 
var internalQuery = internalQueryField.GetValue(query); 
FieldInfo objectQueryField = internalQuery.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Where(f => f.Name.Equals("_objectQuery")).FirstOrDefault(); 
ObjectQuery<int> objectQuery = objectQueryField.GetValue(internalQuery) as ObjectQuery<int>; 

foreach (ObjectParameter objectParam in objectQuery.Parameters) 
{ 
    SqlParameter sqlParam = new SqlParameter(objectParam.Name, objectParam.Value); 
    // Etc... 
} 

我執行的SqlCacheDependency與實體框架。 :-)