2011-08-26 21 views
17

Tôi có đoạn mã sau:Entity Framework 4.1: Không thể đúc từ 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()); 
} 

Về cơ bản, những gì tôi đang cố gắng làm là để xóa một số lượng lớn các dữ liệu từ một ngữ cảnh (có được một truy vấn kết quả, lấy SQL và thực hiện nó). Nhưng tôi gặp sự cố khi truyền result đến ObjectQuery. Trường hợp ngoại lệ cho phép là

Không thể cast đối tượng kiểu 'System.Data.Entity.Infrastructure.DbQuery 1[System.Int32]' to type 'System.Data.Objects.ObjectQuery 1 [System.Int32]'.

Ai có thể đưa ra bất kỳ gợi ý nào để giải quyết vấn đề này không? Cảm ơn!

EDIT: Ladislav giải pháp đầu tiên giúp tôi giải quyết vấn đề, nhưng nó happenned một vấn đề nhỏ với các thông số SQL của truy vấn SQL được tạo ra, tức là truy vấn SQL được tạo ra bởi query.ToString() là thế này:

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

Vấn đề là các biến số @p__linq__0@p__linq__1 không được khai báo và do đó truy vấn đã đưa ra lỗi "Phải khai báo biến vô hướng @p_ linq _0" (tôi chắc chắn nó sẽ cho cùng một lỗi cho biến @p__linq__1). Để "khai báo" chúng tôi cần chuyển chúng làm đối số của ExecuteSqlCommand(). Và như vậy, giải pháp cuối cùng cho câu trả lời đầu tiên là mã dưới đây:

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

Bằng cách này, tôi giả sử các biến được tạo ra luôn có định dạng @p__linq__, trừ khi Entity Framework Đội bóng của Microsoft thay đổi nó trong bất kỳ bản cập nhật EF tương lai. ..

Trả lời

22

Đó là do _database của bạn có nguồn gốc từ DbContextAccountsOfMonth của bạn là DbSet<>. Trong trường hợp này, bạn không thể sử dụng trực tiếp ObjectQueryDbSet<> sản xuất DbQuery<> không thể chuyển đổi thành ObjectQuery<>.

Bạn có thể phải sử dụng DbQuery<> trực tiếp:

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

Hoặc trước tiên bạn phải chuyển đổi ngữ cảnh của bạn để ObjectContext và tạo 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; 

Vấn đề với cách tiếp cận thứ nhất là DbQuery không phục vụ Bộ sưu tập Parameters - chỉ là một ví dụ khác về đơn giản hóa trong API DbContext mà chỉ làm cho việc sử dụng khó hơn.

+0

cảm ơn sự giúp đỡ của bạn! Kiểm tra chỉnh sửa bài đăng của tôi (tôi đã thêm giải pháp cuối cùng) vì nó đã gặp phải một vấn đề nhỏ với các tham số SQL. Dù bằng cách nào, nó được giải quyết! :) – jmpcm

1

Trong trường hợp của tôi, tôi thực sự cần các thông số và tôi thấy cách giải quyết này:

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

Tôi đang thực hiện SqlCacheDependency với Entity Framework. :-)

Các vấn đề liên quan