2013-08-02 15 views
8

Sono estremamente nuovo a linq e framework di entità. Sto cercando di risolvere un problema sul perché il sotto non funziona. L'errore prodotto è "Impossibile creare un valore costante di tipo" Tipo anonimo ". Solo i tipi primitivi o i tipi di enumerazione sono supportati in questo contesto."Impossibile creare un valore costante di tipo "tipo anonimo". Solo i tipi primitivi o tipi di enumerazione sono supportati in questo contesto

Ho provato questo tanti modi diversi ma ancora ottenere un errore relativo ai tipi primitivi. Apprezzerei molto se qualcuno potesse dare un'occhiata al codice qui sotto e spero che indichi dove sta andando male.

 public Entities.BikeData[] GetBikesWithExpiredSyncDeadline(int noOfDays) { 

     using (OfficeEntities cxt = GetContext()) 
     using (ReportingEntities RepCxt = GetReportingContext()) { 
      Data.Repository.Abstract.IBikeRepository BikeRepos = new Data.Repository.Concrete.BikeRepository();     

      var details = (from sd in cxt.BikeDetails 
             where sd.autoreminder == true 
              && (sd.lastremindersent == null || sd.lastremindersent < EntityFunctions.AddDays(DateTime.UtcNow, noOfDays * -1)) 
              && (sd.emailaddress != null && sd.emailaddress.Trim() != "") 
             select new { 
              Serial = sd.Serial, 
              EmailAddress = sd.emailaddress 
             }).ToList(); 

      var resLst = (from r in RepCxt.RegisteredBikes 
          join d in details on r.Serial equals d.Serial 
          join cs in cxt.CompanySettings.ToList() on r.CompanyID equals cs.CompanyID 
          where (!r.lastupdate.HasValue || r.lastupdate < EntityFunctions.AddDays(DateTime.UtcNow, cs.AutoNotificationFrequency * -1)) 
          select new Entities.BikeData { 
           ID = r.ID, 
           Name = r.Ship, 
           Serial = r.Serial, 
           LastUpdate = r.lastupdate, 
           DaysSinceLastSync = (r.lastupdate.HasValue? EntityFunctions.DiffDays(r.lastupdate.Value, DateTime.UtcNow).Value : -1), 
           EmailAddress = (d.EmailAddress == null ? string.Empty : (String.IsNullOrEmpty(d.EmailAddress) ? r.ShipEmailAddress : d.EmailAddress)) 
          }); 

      return resLst.ToArray(); 
     } 
    } 

UPDATE

ho preso un approccio diverso con questo ora con la creazione di una vista così non ho più bisogno di fare il contesto croce si unisce a EF. Speravo potessi essere in grado di aiutarti con il seguito.

Quando eseguo objectQuery.ToTraceString() mi fornisce un SQL valido che restituisce i record nel db, tuttavia il resLst in EntityFramework torna sempre con 0. C'è qualcosa di ovvio sul perché questo sta accadendo?

var resLst = (from ls in cxt.BikeLastUpdates 
          where (!ls.lastupdate.HasValue || ls.lastupdate < EntityFunctions.AddDays(DateTime.UtcNow, ls.AutoNotificationFrequency * -1)) 
          && (ls.autoreminder ==true) 
          && (ls.lastremindersent == null || ls.lastremindersent < EntityFunctions.AddDays(DateTime.UtcNow, 3 * -1)) 
          && (ls.emailaddress !=null && ls.emailaddress.Trim() != "") 
          select new Entities.BikeData{ 
           ID = (ls.ID ?? new Guid()), 
           Name = ls.Bike, 
           Serial = ls.Serial, 
           LastUpdate = ls.lastupdate, 
           EmailAddress = (String.IsNullOrEmpty(ls.emailaddress) ? ls.ShipEmailAddress : ls.emailaddress) 
          }); 

      var objectQuery = resLst as ObjectQuery; 

      return resLst.ToArray(); 
+0

Per il vostro aggiornamento suggerirei di usare [Sql Server Profiler] (htt p: //msdn.microsoft.com/en-us/library/ms181091.aspx) e catturare lo sql che EF sta effettivamente inviando al server. –

+0

Buongiorno amico. Sciocco problema di stringhe di connessione. Vivi e impari :-) – JIbber4568

risposta

5

Il problema è la chiamata ToList() sui dettagli. In EF, è possibile fare riferimento a un oggetto IEnumerable all'interno di una query solo se IEnumerable è di tipo semplice (ad esempio int). Tuttavia, è possibile fare riferimento a un altro IQueryable. Pertanto, l'eliminazione della chiamata a ToList() dovrebbe rendere questo lavoro.

MODIFICA: analogamente, è necessario eliminare la chiamata ToList() su ctx.CompanySettings.

questo avrà il vantaggio di eseguire solo 1 query invece di 2. Se si lascia cadere la ToList() sui dettagli, EF genererà qualcosa come:

SELECT ... 
FROM RegisteredBikes rb 
JOIN (
    /* this is your "details" IQueryable */ 
    SELECT Serial, EmailAddress 
    FROM BikeDetails 
    WHERE ... 
) bd 
    ON rb.Serial = b.Serial 
JOIN CompanySettings cs 
    ON ... 
WHERE ... 

EDIT: per fare questo attraverso i contesti, è necessario portare la query in memoria (ad es. chiamando AsEnumerable() e fare i join rilevanti lì. Se i join agiscono come filtri ed è importante che questi avvengano in SQL, prendere in considerazione l'uso di Contains(). Ad esempio

var serials = details.Select(d => d.Serial); 
var filtered = RepCtxt.RegisteredBikes.Where(r => details.Contains(r.Serial); 
+0

Grazie per quello. La ragione per cui è fatta in questo modo è che dobbiamo unirci al contesto incrociato. Per quanto ne so senza la .ToList() non siamo in grado di interrogare il contesto incrociato. C'è un approccio diverso con questo che dovrei forse prendere per consentire i cross context join? – JIbber4568

+0

@ JIbber4568 per accedere al contesto incrociato, è necessario richiamare in memoria l'intera tabella delle impostazioni aziendali e filtrare utilizzando WHERE IN() (Contiene in EF). – ChaseMedallion

+0

Grazie per il vostro aiuto con questo. Ho adottato un approccio leggermente diverso con questo, ma ora sto avendo problemi con Entity Framework che eredita i risultati dal DB. C'è qualcosa di ovvio nell'aggiornamento sopra che potrebbe causare questo? Grazie – JIbber4568

Problemi correlati