2009-04-24 27 views
33

Sử dụng lệnh LINQ và LINQ to SQL DataContext, Im cố gắng để dụ một Entity gọi là "Produccion" từ DataContext của tôi theo cách này:Không được phép xây dựng rõ ràng loại đối tượng '###' trong truy vấn.

Demo.View.Data.PRODUCCION pocoProduccion = 
(
    from m in db.MEDICOXPROMOTORs 
    join a in db.ATENCIONs on m.cmp equals a.cmp 
    join e in db.EXAMENXATENCIONs on a.numeroatencion equals e.numeroatencion 
    join c in db.CITAs on e.numerocita equals c.numerocita 
    where e.codigo == codigoExamenxAtencion 
    select new Demo.View.Data.PRODUCCION 
    { 
     cmp = a.cmp, 
     bonificacion = comi, 
     valorventa = precioEstudio, 
     codigoestudio = lblCodigoEstudio.Content.ToString(), 
     codigopaciente = Convert.ToInt32(lblCodigoPaciente.Content.ToString()), 
     codigoproduccion = Convert.ToInt32(lblNroInforme.Content.ToString()), 
     codigopromotor = m.codigopromotor, 
     fecha = Convert.ToDateTime(DateTime.Today.ToShortDateString()), 
     numeroinforme = Convert.ToInt32(lblNroInforme.Content.ToString()), 
     revisado = false, 
     codigozona = (c.codigozona.Value == null ? Convert.ToInt32(c.codigozona) : 0), 
     codigoclinica = Convert.ToInt32(c.codigoclinica), 
     codigoclase = e.codigoclase, 
    } 
).FirstOrDefault(); 

Trong khi thực hiện đoạn mã trên, tôi nhận được lỗi sau mà stack trace được bao gồm:

System.NotSupportedException was caught 
    Message="The explicit construction of the entity type 'Demo.View.Data.PRODUCCION' in a query is not allowed." 
    Source="System.Data.Linq" 
    StackTrace: 
     en System.Data.Linq.SqlClient.QueryConverter.VisitMemberInit(MemberInitExpression init) 
     en System.Data.Linq.SqlClient.QueryConverter.VisitInner(Expression node) 
     en System.Data.Linq.SqlClient.QueryConverter.Visit(Expression node) 
     en System.Data.Linq.SqlClient.QueryConverter.VisitSelect(Expression sequence, LambdaExpression selector) 
     en System.Data.Linq.SqlClient.QueryConverter.VisitSequenceOperatorCall(MethodCallExpression mc) 
     en System.Data.Linq.SqlClient.QueryConverter.VisitMethodCall(MethodCallExpression mc) 
     en System.Data.Linq.SqlClient.QueryConverter.VisitInner(Expression node) 
     en System.Data.Linq.SqlClient.QueryConverter.Visit(Expression node) 
     en System.Data.Linq.SqlClient.QueryConverter.VisitFirst(Expression sequence, LambdaExpression lambda, Boolean isFirst) 
     en System.Data.Linq.SqlClient.QueryConverter.VisitSequenceOperatorCall(MethodCallExpression mc) 
     en System.Data.Linq.SqlClient.QueryConverter.VisitMethodCall(MethodCallExpression mc) 
     en System.Data.Linq.SqlClient.QueryConverter.VisitInner(Expression node) 
     en System.Data.Linq.SqlClient.QueryConverter.ConvertOuter(Expression node) 
     en System.Data.Linq.SqlClient.SqlProvider.BuildQuery(Expression query, SqlNodeAnnotations annotations) 
     en System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query) 
     en System.Data.Linq.DataQuery`1.System.Linq.IQueryProvider.Execute[S](Expression expression) 
     en System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source) 
     en Demo.View.InformeMedico.realizarProduccionInforme(Int32 codigoExamenxAtencion, Double precioEstudio, Int32 comi) en D:\cs_InformeMedico\app\InformeMedico.xaml.cs:línea 602 
     en Demo.View.InformeMedico.UpdateEstadoEstudio(Int32 codigo, Char state) en D:\cs_InformeMedico\app\InformeMedico.xaml.cs:línea 591 
     en Demo.View.InformeMedico.btnGuardar_Click(Object sender, RoutedEventArgs e) en D:\cs_InformeMedico\app\InformeMedico.xaml.cs:línea 683 
    InnerException: 

Bây giờ có được phép trong LINQ2SQL không?

Trả lời

20

Thực thể có thể được tạo bên ngoài các truy vấn và được chèn vào kho dữ liệu bằng cách sử dụng DataContext. Sau đó, bạn có thể truy xuất chúng bằng truy vấn. Tuy nhiên, bạn không thể tạo các thực thể như là một phần của truy vấn.

+12

thats có nghĩa là nhiều dòng mã đúng? –

+0

Làm cách nào để chuyển các giá trị đã chọn từ truy vấn trả về đó đến một Thực thể, tôi có nghĩa là không sử dụng các thành viên, giống như "varReturningQuery as ProductionEntity"? –

9

Tôi vừa gặp sự cố tương tự.

Tôi đã tìm thấy một giải pháp rất dễ dàng.

var a = att as Attachment; 

Func<Culture, AttachmentCulture> make = 
    c => new AttachmentCulture { Culture = c }; 

var culs = from c in dc.Cultures 
      let ac = c.AttachmentCultures.SingleOrDefault( 
              x => x.Attachment == a) 
      select ac == null ? make(c) : ac; 

return culs; 
+1

chọn có thể được viết tốt hơn là chọn ac ?? Làm cho c); – recursive

+2

Giải pháp tuyệt vời - cảm ơn! Bất kỳ ý tưởng tại sao điều này không được phép mà không làm điều này? – Whisk

+1

@Whisk - trong trường hợp bạn vẫn quan tâm, tôi đã tìm thấy http://social.msdn.microsoft.com/forums/en-US/linqprojectgeneral/thread/1ce25da3-44c6-407d-8395-4c146930004b - '... Xây dựng các cá thể thực thể theo cách thủ công khi một phép chiếu gây ô nhiễm bộ nhớ cache với các đối tượng có khả năng bị sai ... ' –

0

Trong cuốn sách "70-515 Web Phát triển ứng dụng với Microsoft .NET Framework 4 - Tự nhịp độ bộ đào tạo", trang 638 có ví dụ sau đây để kết quả đầu ra cho một đối tượng mạnh mẽ gõ:

IEnumerable<User> users = from emp in employees where emp.ID !=0 
    select new User 
    { 
    Name = emp.First + " " + emp.Last, 
    EmployeeId = emp.ID 
    } 

Lời khuyên Mark Pecks xuất hiện mâu thuẫn với cuốn sách này - tuy nhiên, đối với tôi ví dụ này vẫn hiển thị lỗi ở trên là tốt, khiến tôi hơi bối rối. Điều này có liên quan đến sự khác biệt phiên bản không? Mọi đề xuất đều được chào đón.

+5

Ví dụ trên hoạt động nếu "Người dùng" không phải là một phần của DataContext. – Stone

13

Tôi thấy giới hạn này rất khó chịu và sẽ đi ngược lại xu hướng chung của việc không sử dụng SELECT * trong truy vấn.

Vẫn với các loại ẩn danh C# có giải pháp thay thế, bằng cách tìm nạp các đối tượng vào một loại ẩn danh, sau đó sao chép nó vào đúng loại.

Ví dụ:

var q = from emp in employees where emp.ID !=0 
select new {Name = emp.First + " " + emp.Last, EmployeeId = emp.ID } 
var r = q.ToList(); 
List<User> users = new List<User>(r.Select(new User 
    { 
     Name = r.Name, 
     EmployeeId = r.EmployeeId 
    })); 

Và trong trường hợp khi chúng ta đối phó với một giá trị duy nhất (như trong tình huống được mô tả trong câu hỏi) nó thậm chí còn dễ dàng hơn, và chúng ta chỉ cần sao chép trực tiếp các giá trị:

var q = from emp in employees where emp.ID !=0 
select new { Name = emp.First + " " + emp.Last, EmployeeId = emp.ID } 
var r = q.FirstOrDefault(); 
User user = new User { Name = r.Name, EmployeeId = r.ID }; 

Nếu tên của các thuộc tính phù hợp với các cột cơ sở dữ liệu chúng ta có thể làm điều đó thậm chí đơn giản trong truy vấn, bằng cách thực hiện chọn

var q = from emp in employees where emp.ID !=0 
select new { emp.First, emp.Last, emp.ID } 

Người ta có thể tiếp tục và viết một biểu thức lambda có thể sao chép tự động dựa trên tên thuộc tính mà không cần chỉ định các giá trị explictly.

+0

Tôi đồng ý giới hạn này rất khó chịu. Tuy nhiên, lời gọi tới 'ToList' trong giải pháp của bạn sẽ đưa kết quả vào bộ nhớ, điều này có lẽ không được mong muốn đối với các tập dữ liệu lớn. –

8

Tôi đã tìm thấy rằng nếu bạn làm một ToList() trên các truy vấn trước khi cố gắng để contruct đối tượng mới nó hoạt động

+4

Nhưng điều đó làm mất hiệu suất trì hoãn. –

7

Đây là một cách giải quyết:

  1. Tạo một lớp dẫn xuất từ ​​LINQ của bạn đến lớp SQL.Tôi giả định rằng lớp L2S mà bạn muốn quay trở lại là thứ tự:

    internal class OrderView : Order { } 
    
  2. Bây giờ viết các truy vấn theo cách này:

    var query = from o in db.Order 
          select new OrderView // instead of Order 
          { 
           OrderID = o.OrderID, 
           OrderDate = o.OrderDate, 
           // etc. 
          }; 
    
  3. Cast kết quả trở lại vào thứ tự, như thế này:

    return query.Cast<Order>().ToList(); // or .FirstOrDefault() 
    
  4. (hoặc sử dụng một cái gì đó hợp lý hơn, như BLToolkit/LINQ to DB)

Lưu ý: Tôi chưa thử nghiệm xem liệu tính năng theo dõi có hoạt động hay không; nó hoạt động để lấy dữ liệu, đó là những gì tôi cần.

+1

Rực rỡ! Mặc dù tôi không cần phải quay lại – irfandar

+0

Tôi đồng ý đây là một giải pháp tuyệt vời! Nếu có một lý do kỹ thuật tại sao tôi không nên dự án lên một lớp thực thể thì đó là tốt tôi sẽ không, nhưng những người muốn xác định lại một lớp mới (có khả năng dài) với hình dạng chính xác giống nhau? Không ai, đó là ai. Giải pháp này giải quyết nó mà không định nghĩa lại rõ ràng. Công việc tuyệt vời pbz, đóng đinh nó. –

5

Tôi xây dựng một loại vô danh, sử dụng IEnumerable (trong đó duy trì thực thi hoãn lại), và sau đó tái cấu trúc đối tượng dữ liệu văn bản. Cả hai nhân viên và quản lý là những đối tượng DataContext:

var q = dc.Employees.Where(p => p.IsManager == 1) 
      .Select(p => new { Id = p.Id, Name = p.Name }) 
      .AsEnumerable()  
      .Select(item => new Manager() { Id = item.Id, Name = item.Name }); 
+0

Sẽ không 'AsEnumerable' gây tải háo hức? –

0

Tôi tìm thấy một cách giải quyết cho vấn đề mà thậm chí cho phép bạn giữ lại kết quả của bạn như IQueryale, vì vậy nó không thực sự thực hiện truy vấn cho đến khi bạn muốn nó được thực thi (như nó sẽ với phương thức ToList()).

Vì vậy, LINQ không cho phép bạn tạo một thực thể như một phần của truy vấn? Bạn có thể chuyển nhiệm vụ đó vào cơ sở dữ liệu và tạo một hàm sẽ lấy dữ liệu bạn muốn. Sau khi bạn nhập hàm vào ngữ cảnh dữ liệu của mình, bạn chỉ cần đặt loại kết quả thành loại bạn muốn.


tôi phát hiện ra về vấn đề này khi tôi đã phải viết một đoạn mã mà sẽ tạo ra một IQueryable<T> trong đó các mặt hàng không thực sự tồn tại trong bảng chứa T.

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