2013-04-19 9 views
13

ho una struttura di classe simile a questo:Posso restituire un insieme di molteplici tipi derivati ​​da Query Dapper

public abstract class Device 
{ 
    public int DeviceId { get; set; } 
    //Additional Properties 
} 

public class DeviceA : Device 
{ 
    //Specific Behaviour 
} 

public class DeviceB : Device 
{ 
    //Specific Behaviour 
} 

Ho bisogno di recuperare un elenco di dispositivi, o di un singolo dispositivo che viene istanziato come l'appropriato tipo derivato (basato su un valore Type nel Device Record nel DB). Cioè, la collezione di oggetti Device dovrebbe contenere un numero di oggetti con tipi diversi, tutti derivati ​​da Device.

Ho implementato questo modo nel modo seguente, ma qualcosa non mi sembra giusto.

public static IEnumerable<Device> AllDevices() 
{ 
    using (var connection = CreateConnection()) 
    { 
     connection.Open(); 
     return connection.Query<dynamic>("SELECT * FROM Device").Select<dynamic, Device>(d => 
      { 
       Device device = null; 
       if (d.DeviceTypeID == 1) 
        device = new DeviceA(); 
       else if (d.DeviceTypeID == 2) 
        device = new DeviceB(); 
       else throw new Exception("Unknown Device"); 
       device.DeviceId = d.DeviceID; 
       return device; 
      }); 
    } 
} 

È questo il modo corretto per ottenere ciò utilizzando Dapper oppure esiste un approccio migliore?

+0

Potrebbe essere reso più leggibile se si divide la query in 2 query separate. Uno di DeviceType 1 e uno per deviceType 2, quindi combinato i due set di risultati per il tuo ritorno, ma a parte questo, questa sembra essere una buona soluzione. – DavidEdwards

+0

Non proprio quello che sto cercando - in particolare per il caso d'uso quando si recupera un singolo dispositivo, dato che non conosciamo il tipo di dispositivo in anticipo. (Ad esempio, Ottieni dispositivo per numero di serie o qualche altro identificatore). Grazie, però, David. – GaryJL

+0

Se sei interessato a monitorare i progressi su questa funzione: https://github.com/StackExchange/dapper-dot-net/issues/262 – ajbeaven

risposta

3

Nella build corrente è probabilmente l'unica opzione (soprattutto perché il tipo di base è astratto). Tuttavia, non sarebbe irragionevole pensare a modi per suggerire un sistema ereditario discriminato. Non è qualcosa che abbiamo fatto finora semplicemente perché non è venuto fuori, ma non sembra impossibile. Il problema più grande che riesco a vedere (a parte il litigio con IL, ovviamente) è semplicemente il modo in cui esprimiamo la relazione.

+0

Grazie, Marc. Quale sarebbe la differenza se il tipo di base non fosse astratto? – GaryJL

+0

@GaryJL Non ho davvero menzionato l'abstract; al momento creerà solo il tipo dichiarato (presumibilmente il tipo base); se ci fosse qualcosa di più "intelligente" in corso, mi aspetterei che i tipi di base astratti funzionino, a patto che non debba mai creare quel tipo, ovviamente # –

+1

Sono sorpreso che questo non sia mai venuto fuori prima. Mi sembra che un'eredità come questa sia abbastanza comune in molti database. – ajbeaven

0

ho si avvicinò con questa soluzione:

using (IDbConnection db = new MySqlConnection(ConfigurationManager.ConnectionStrings["yourConnection"].ConnectionString)) 
     { 
      return db.Query<dynamic, DeviceA, DeviceB, Device>(@" 
       Select 
        Discriminator, 
        ... 
       From Device", (d, da, db) => 
       { 
        if (p.Discriminator == "DeviceA") 
        { 
         return new DeviceA(); 
        } 
        else if (p.Discriminator == "DeviceB") 
        { 
         return new DeviceB(); 
        } 
        return d; 
       });  

Suona complicato, ma funziona!

Spero che possa aiutarti. }

Problemi correlati