entity framework4.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)result; string sql = string.Format( "DELETE FROM [AccountsOnMonth] WHERE [AccountsOnMonth].[Id] IN ({0})", query.ToTraceString() ); var parameters = new List(); 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]”。
任何人都可以提供任何解决方案吗? 谢谢!
编辑: Ladislav第一个解决方案帮我解决了这个问题,但它在生成的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)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__
格式,除非Microsoft的entity framework团队在任何未来的EF更新中更改它…
这是因为您的_database
是从DbContext
派生的,而您的AccountsOfMonth
是DbSet<>
。 在这种情况下,您不能直接使用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)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(); var resut = from acm in set where ((acm.Year == year) && (acm.Month == month)) select acm.Id;
第一种方法的问题是DbQuery
不提供Parameters
集合 – 只是DbContext API中的另一个简化示例,它只会使其更难使用。
在我的情况下,我真的需要参数,我发现这个解决方法:
var query = (DbQuery)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 objectQuery = objectQueryField.GetValue(internalQuery) as ObjectQuery ; foreach (ObjectParameter objectParam in objectQuery.Parameters) { SqlParameter sqlParam = new SqlParameter(objectParam.Name, objectParam.Value); // Etc... }
我正在使用Entity Framework实现SqlCacheDependency。 🙂