2009-04-24 5 views
33

Mit Linq Befehlen und LINQ to SQL Datacontext, versuchen Im zu Beispiel eines Entity „Produccion“ von meiner Datacontext auf diese Weise genannt:Explizite Konstruktion des Entitätstyps '###' in Abfrage ist nicht erlaubt.

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

Während den obigen Code ausgeführt wird, ich die folgende Fehlermeldung erhalten, dass die Stack-Trace ist enthalten:

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: 

Ist das jetzt in LINQ2SQL erlaubt?

Antwort

20

Entitäten können außerhalb von Abfragen erstellt und mithilfe eines DataContext in den Datenspeicher eingefügt werden. Sie können sie dann mithilfe von Abfragen abrufen. Sie können Entitäten jedoch nicht als Teil einer Abfrage erstellen.

+12

das ist, bedeutet mehr Zeilen Code Recht? –

+0

Wie kann ich die Auswahlwerte aus dieser zurückgebenden Abfrage an eine Entität übergeben, ich meine nicht Mitglieder verwenden, genau wie "varReturningQuery als ProductionEntity"? –

9

Ich lief gerade in das gleiche Problem.

Ich fand eine sehr einfache Lösung.

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

auswählen kann besser geschrieben werden als wählen ac ?? machen (c); – recursive

+2

Ausgezeichnete Lösung - danke! Irgendwelche Ideen, warum dies nicht erlaubt ist, ohne dies zu tun? – Whisk

+1

@Whisk - falls Sie noch interessiert sind, fand ich http://social.msdn.microsoft.com/forums/en-US/linqprojectgeneral/thread/1ce25da3-44c6-407d-8395-4c146930004b - '... Das manuelle Konstruieren von Entitätsinstanzen als eine Projektion verschmutzt den Cache mit potenziell fehlerhaften Objekten ... ' –

0

Im Buch "70-515 Web-Anwendungen Entwicklung mit Microsoft .NET Framework 4 - Selbststudium Training Kit", Seite 638 hat das folgende Beispiel zur Ausgabe von Ergebnissen zu einem stark typisierte Objekt:

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

Mark Pecks Ratschläge scheinen diesem Buch zu widersprechen - allerdings zeigt dieses Beispiel für mich immer noch den obigen Fehler, was mich etwas verwirrt. Ist dies mit Versionsunterschieden verbunden? Irgendwelche Vorschläge willkommen.

+5

Das obige Beispiel funktioniert, wenn "Benutzer" nicht Teil des DataContext ist. – Stone

13

Ich finde diese Einschränkung sehr ärgerlich und gegen den allgemeinen Trend der Verwendung von SELECT * in Abfragen.

Immer noch mit anonymen C# -Typen gibt es eine Problemumgehung, indem Sie die Objekte in einen anonymen Typ abrufen und dann in den richtigen Typ kopieren.

Zum Beispiel:

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

Und in dem Fall, wenn wir mit einem einzigen Wert beschäftigen (wie in der Situation, in der Frage beschrieben) ist es noch einfacher, und wir müssen nur die Werte direkt kopieren:

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

Wenn der Name der Eigenschaften entsprechen den Datenbankspalten wir tun können, es noch einfacher in der Abfrage, durch Auswahl tun

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

Man könnte weitermachen und einen Lambda-Ausdruck schreiben, der basierend auf dem Eigenschaftsnamen automatisch kopieren kann, ohne die Werte explizit angeben zu müssen.

+0

Ich stimme zu, die Einschränkung ist sehr ärgerlich. Der Aufruf von 'ToList' in Ihrer Lösung speichert die Ergebnisse jedoch im Speicher, was für große Datenmengen wahrscheinlich nicht wünschenswert ist. –

8

Ich habe festgestellt, dass, wenn Sie einen .ToList tun() auf der Abfrage, bevor neue Objekte zu contruct versuchen, es funktioniert

+4

Aber das verliert die verzögerte Ausführung. –

7

Hier ist eine andere Abhilfe:

  1. eine Klasse machen, die von Ihrem LINQ ableitet zu SQL-Klasse.Ich gehe davon aus, dass die L2S-Klasse, die Sie zurückkommen wollen, ist Ordnung:

    internal class OrderView : Order { } 
    
  2. nun die Abfrage auf diese Weise schreiben:

    var query = from o in db.Order 
          select new OrderView // instead of Order 
          { 
           OrderID = o.OrderID, 
           OrderDate = o.OrderDate, 
           // etc. 
          }; 
    
  3. Guss das Ergebnis wieder in Ordnung, wie folgt aus:

    return query.Cast<Order>().ToList(); // or .FirstOrDefault() 
    
  4. (oder verwenden Sie etwas vernünftiger, wie BLToolkit/LINQ to DB)

Hinweis: Ich habe nicht getestet, ob Tracking funktioniert oder nicht; es funktioniert, um Daten zu erhalten, was ich brauchte.

+1

Brilliant! Obwohl ich nicht – irfandar

+0

zurückwerfen musste, stimme ich zu, dass dies eine großartige Lösung ist! Wenn es einen technischen Grund gibt, warum ich nicht auf eine Entitätsklasse projizieren sollte, dann ist das in Ordnung, aber wer will eine neue (möglicherweise lange) Klasse mit der exakt gleichen Form neu definieren? Niemand, das ist wer. Diese Lösung löst es ohne explizite Neudefinition. Tolle Arbeit, pbz, genagelt. –

5

Ich konstruiere einen anonymen Typ, verwende IEnumerable (wodurch die verzögerte Ausführung beibehalten wird), und re-konstruiere dann das Datenkontextobjekt. Beide Mitarbeiter und Geschäftsführer sind Datacontext-Objekte:

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

Würde 'AsEnumerable' nicht zu eifrigem Laden führen? –

0

fand ich eine andere Abhilfe für das Problem, das können Sie sogar Ihr Ergebnis als IQueryale behalten, damit es nicht die Abfrage tatsächlich ausführen, bis Sie es möchten ausgeführt werden (wie es würde mit der ToList() Methode).

So Linq ermöglicht es Ihnen nicht, eine Entität als Teil der Abfrage zu erstellen? Sie können diese Aufgabe in die Datenbank selbst verschieben und eine Funktion erstellen, die die gewünschten Daten erfasst. Nachdem Sie die Funktion in Ihren Datenkontext importiert haben, müssen Sie nur den Ergebnistyp auf den gewünschten festlegen.


ich davon erfuhr, als ich ein Stück Code zu schreiben hatte, die eine IQueryable<T>, in der die Elemente in der Tabelle T. enthalten, nicht wirklich existieren produzieren würde

Verwandte Themen