2011-08-26 13 views
17

Ho il seguente codice:Entity Framework 4.1: Impossibile eseguire il cast da DBQuery a 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()); 
} 

In sostanza, quello che sto cercando di fare è di eliminare una massa di dati da un contesto (ottenere una query risultato, ottenere SQL ed eseguirlo). Ma sto riscontrando un problema durante la trasmissione di result a ObjectQuery. L'eccezione che dà è

Impossibile eseguire il cast oggetto di tipo 'System.Data.Entity.Infrastructure.DbQuery 1[System.Int32]' to type 'System.Data.Objects.ObjectQuery 1 [System.Int32]'.

Qualcuno può dare qualche suggerimento per risolvere questo? Grazie!

EDIT: prima soluzione Ladislav ha aiutato a risolvere il problema, ma hanno rubato un piccolo problema con i parametri SQL della query SQL generato, vale a dire la query SQL generato da query.ToString() era questo:

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)) 

Il problema era che le variabili @p__linq__0 e @p__linq__1 dove non erano dichiarate e quindi la query dava l'errore "Devo dichiarare la variabile scalare @p_ linq _0" (sono sicuro che darebbe lo stesso errore alla variabile @p__linq__1). Per "dichiararli" ho bisogno di passarli come argomenti dello ExecuteSqlCommand(). E così, la soluzione finale per la risposta iniziale è il codice qui sotto:

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) 
    ); 
} 

A proposito, ho assumere le variabili generati da sempre hanno il formato @p__linq__, a meno che squadra Entity Framework di Microsoft cambia in qualsiasi aggiornamento EF futuro. ..

risposta

22

Questo perché il tuo _database è derivato da DbContext e il tuo AccountsOfMonth è DbSet<>. In tal caso non è possibile utilizzare ObjectQuery direttamente perché DbSet<> produce DbQuery<> che non è convertibile in ObjectQuery<>.

È necessario usare sia DbQuery<> direttamente:

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() 
); 

Oppure è necessario prima convertire il contesto per ObjectContext e creare 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; 

Il problema di primo approccio è che non offre DbQuery Collezione Parameters - solo un altro esempio di semplificazione nell'API di DbContext che rende solo più difficile l'utilizzo.

+0

grazie per il vostro aiuto! Controlla la modifica del mio post (ho aggiunto la soluzione finale) perché ha avuto un piccolo problema con i parametri SQL. Ad ogni modo, è risolto! :) – jmpcm

1

Nel mio caso avevo davvero bisogno i parametri e ho trovato questa soluzione:

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... 
} 

sto implementando SqlCacheDependency con Entity Framework. :-)

Problemi correlati