2009-04-24 6 views
33

Utilizzo dei comandi Linq e LINQ to SQL DataContext, Im cercando di esempio un'entità chiamata "Produccion" dal mio DataContext in questo modo:La costruzione esplicita del tipo di entità "###" nella query non è consentita.

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

Durante l'esecuzione del codice di cui sopra, sto ottenendo il seguente errore che la stack trace è incluso:

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: 

È ora consentito in LINQ2SQL?

risposta

20

Le entità possono essere create al di fuori delle query e inserite nell'archivio dati utilizzando un DataContext. È quindi possibile recuperarli utilizzando le query. Tuttavia, non è possibile creare entità come parte di una query.

+12

questo è significa più linee di codice destra? –

+0

Come posso passare i valori selezionati da quella query di ritorno a un'entità, voglio dire non usare membri, proprio come "varReturningQuery come ProductionEntity"? –

9

Ho appena avuto lo stesso problema.

Ho trovato una soluzione molto semplice.

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

selezionare potrebbe essere meglio scritto come selezionare ac ?? effettuare (c); – recursive

+2

Ottima soluzione - grazie! Qualche idea del perché questo non è permesso senza fare questo? – Whisk

+1

@Whisk - nel caso in cui tu sia ancora interessato, ho trovato http://social.msdn.microsoft.com/forums/en-US/linqprojectgeneral/thread/1ce25da3-44c6-407d-8395-4c146930004b - '... La costruzione manuale delle istanze di entità come proiezione inquina la cache con oggetti potenzialmente malformati ... ' –

0

all'interno del libro "Lo sviluppo di applicazioni Web con 70-515 Microsoft .NET Framework 4 - auto ritmo kit di formazione", pagina 638 ha il seguente esempio per risultati di output a un oggetto fortemente tipizzato:

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

Il consiglio di Mark Pecks sembra contraddire questo libro - tuttavia, per me questo esempio mostra ancora l'errore di cui sopra, lasciandomi un po 'confuso. Questo è legato alle differenze di versione? Qualsiasi suggerimento benvenuto.

+5

L'esempio precedente funziona se "Utente" non fa parte di DataContext. – Stone

13

Sto riscontrando che questa limitazione è molto fastidiosa e va contro la tendenza comune di non utilizzare SELECT * nelle query.

Ancora con i tipi anonimi C# è possibile ovviare al problema, recuperando gli oggetti in un tipo anonimo e quindi copiandoli nel tipo corretto.

Ad esempio:

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

E nel caso in cui abbiamo a che fare con un unico valore (come nella situazione descritta nella questione) è ancora più facile, e abbiamo solo bisogno di copiare direttamente i valori:

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

Se il nome delle proprietà corrispondono le colonne del database che possiamo fare ancora più semplice nella query, facendo selezionare

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

Si potrebbe andare avanti e scrivere un'espressione lambda che può copiare automaticamente in base al nome della proprietà, senza la necessità di specificare esplicitamente i valori.

+0

Sono d'accordo che la limitazione è molto fastidiosa. La chiamata a 'ToList' nella soluzione, tuttavia, metterà i risultati in memoria, che probabilmente non è desiderabile per i big data set. –

8

Ho scoperto che se si fa un ToList() sulla query prima di provare a contruct nuovi oggetti funziona

+4

Ma questo perde l'esecuzione differita. –

7

Ecco un'altra soluzione:

  1. fare una classe che deriva dal LINQ alla classe SQL.Sto assumendo che la classe L2S che si desidera tornare è d'ordine:

    internal class OrderView : Order { } 
    
  2. Ora scrivere la query in questo modo:

    var query = from o in db.Order 
          select new OrderView // instead of Order 
          { 
           OrderID = o.OrderID, 
           OrderDate = o.OrderDate, 
           // etc. 
          }; 
    
  3. Fusioni il risultato di nuovo in ordine, in questo modo:

    return query.Cast<Order>().ToList(); // or .FirstOrDefault() 
    
  4. (o usare qualcosa di più sensato, come BLToolkit/LINQ to DB)

Nota: non ho provato a verificare se il tracciamento funziona o meno; funziona per recuperare i dati, che è quello che mi serviva.

+1

Brillante! Anche se non ho avuto bisogno di tornare indietro – irfandar

+0

sono d'accordo che questa è un'ottima soluzione! Se c'è una ragione tecnica per cui non dovrei proiettare su una classe di entità allora va bene non lo farò, ma chi vuole ridefinire una nuova (potenzialmente lunga) classe con la stessa forma esatta? Nessuno, ecco chi. Questa soluzione la risolve senza una ridefinizione esplicita. Ottimo lavoro, inchiodato. –

5

Costruisco un tipo anonimo, utilizzo IEnumerable (che conserva l'esecuzione posticipata), quindi ricalcolo l'oggetto datacontext. Sia i dipendenti e manager sono oggetti 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

Non 'AsEnumerable' causa il caricamento di eager? –

0

ho trovato un'altra soluzione per il problema che ti permette anche di conservare il risultato come IQueryale, quindi in realtà non eseguire la query fino a quando si desidera che venga eseguito (come sarebbe con il metodo ToList()).

Quindi linq non consente di creare un'entità come parte della query? È possibile spostare tale attività nel database stesso e creare una funzione che catturerà i dati desiderati. Dopo aver importato la funzione nel contesto dei dati, è sufficiente impostare il tipo di risultato su quello desiderato.


ho scoperto questo quando ho dovuto scrivere un pezzo di codice che produrrebbe un IQueryable<T> in cui non esistono effettivamente le voci nella tabella contenente T.

Problemi correlati