我有以下代码:
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]'。
任何人都可以提供任何解决方案吗?谢谢!
编辑: 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”(I确定它会为变量@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__
,除非Microsoft的实体框架团队在以后的任何EF更新中对其进行更改...
答案 0 :(得分:23)
这是因为您的_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<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
不提供{{1}}集合 - 只是DbContext API中的另一个简化示例,它只会使其更难使用。
答案 1 :(得分: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...
}
我正在使用Entity Framework实现SqlCacheDependency。 : - )