2009-05-15 8 views
9

Dato due database di schema identico, esiste un modo semplice per trasferire i record tra i due? Sto usando LINQ to SQL in quanto ho bisogno di eseguire alcune operazioni aggiuntive lungo la strada e avere oggetti che rappresentano i record che sto trasferendo rende molto più facile. Questa è un'app helper su piccola scala, quindi SSIS è probabilmente eccessivo e SQLBulkCopy non mi consente di interrogare facilmente gli oggetti lungo il percorso.Utilizzo di LINQ to SQL per la copia tra database

Quello che mi piacerebbe fare è questo:

public static void TransferCustomer 
        (DBDataContext DCSource, 
         DBDataContext DCDest, 
         int CustomerID) 
{ 
    Customer customer; 
    using (DCSource = new DBDataContext(SourceConnStr)) 
    { 
    customer = DCSource.Customers 
         .Where(c => c.CustomerID == CustomerID) 
         .Single(); 
    } 

    using (DCDest = new DBDataContext(DestConnStr)) 
    { 
    DCDest.Customers.InsertOnSubmit(customer); 
    DCDest.SubmitChanges(); 
    } 
} 

Ma per ovvie ragioni, che genera un'eccezione con il messaggio:

Un tentativo è stato fatto per Allega o Aggiungi un entità che non è nuova, forse essendo stata caricata da un altro DataContext. Questo non è supportato.

posso ottenere tutto questo facendo una copia dell'oggetto in questo modo:

public static Customer Clone(this Customer customer) 
{ 
    return new Customer() 
    { 
    Name = customer.Name, 
    Email = customer.Email 
    etc... 
    }; 
} 

e quindi inserendo l'oggetto clonato. Se copio solo i campi in questione, e non tutti i riferimenti che rappresentano le relazioni tra tabelle, questo funziona correttamente. Tuttavia è un po 'prolisso e il modo in cui sto facendo ha bisogno di assegnare manualmente ogni campo nel metodo Clone. Qualcuno potrebbe suggerire modi per semplificare questo processo? Le due cose che mi piacerebbe sapere è:

  1. Può LINQ to SQL fare questo in un modo più semplice,
  2. C'è un bel modo di utilizzare la riflessione per fare una copia che inserire?

Grazie mille!

risposta

0

È un esercizio puramente accademico?

Se non mi sarebbe seriamente pensare di utilizzare SSIS: http://msdn.microsoft.com/en-us/library/ms141026.aspx invece, o, in mancanza di Rhino ETL:. http://ayende.com/Blog/archive/2008/01/16/Rhino-ETL-2.0.aspxfor trasferire dati tra database [link testuale] [1]

+1

Questo è vero, ma è solo un'applicazione aiutante leggero per me da usare. Non prevedo il trasferimento di più di 50 righe su più tabelle in ogni batch, quindi penso che SSIS sia probabilmente eccessivo. La mia attuale soluzione che utilizza un metodo clone per oggetto funziona molto bene, ma sembra poco elegante. Ho bisogno di aggiungere altri tavoli, quindi ho voluto trovare un modo migliore prima di scrivere più metodi di clonazione! –

3

Ecco un modo per poco profonda clone oggetti LINQ (omettendo la chiave primaria): Copy Linq Objects.

Potrebbe essere modificato per utilizzare il meta-modello se non si utilizzano gli attributi. Quindi tutto ciò di cui hai bisogno sono 2 contesti dati (una fonte, una destinazione).

In alternativa, si poteva guardare SqlBulkCopy - vedere Copy from one database table to another C#

+0

Questo è davvero utile, grazie. Uso le classi di entità generate automaticamente in modo che abbiano tutto il markup necessario per utilizzare il metodo clone. Sembra ancora come se LINQ to SQL lo rendesse più facile, ma se nessuno sa come farlo, questo mi farà risparmiare un sacco di tempo. –

0

Perché utilizzare LINQ per fare questo? Sembra un po 'di spreco per un framework per intralciare quando è possibile utilizzare DTS di SQL Server.

+0

Non hai nemmeno bisogno di DTS; SqlBulkCopy funzionerebbe e si tratta di circa 5 righe di codice. –

+0

Devo essere in grado di eseguire alcune operazioni extra lungo la strada - in questo caso, avere classi di entità mi semplifica la vita in altri modi ... So che questo non è il modo migliore per trasferire i record ma ce ne sono alcuni altri fattori che mi fanno desiderare di usare LINQ. –

+0

Penso che tu possa fare cose personalizzate con DTS. Non sono troppo sicuro di quanto sia flessibile. Penso che valga la pena indagare se non trovi una risposta qui. – uriDium

0

Io uso il DataContractCloner di staccare LINQ to SQL entità:

/// <summary> 
/// Serializes the entity to XML. 
/// </summary> 
/// <returns>String containing serialized entity.</returns> 
public string Serialize() 
{ 
    return DataContractCloner.Serialize<Organization>(this); 
} 

/// <summary> 
/// Deserializes the entity from XML. 
/// </summary> 
/// <param name="xml">Serialized entity.</param> 
/// <returns>Deserialized entity.</returns> 
public static Organization Deserialize(string xml) 
{ 
    return DataContractCloner.Deserialize<Organization>(xml); 
} 

Tutto LINQ to SQL entità sono già annotati, quindi questo crea un clone attaccabile che in seguito sarà possibile ricollegare con un alcuni avvertimenti. In primo luogo, le relazioni con le chiavi esterne verranno risolte, quindi è necessario inserire in ordine di dipendenza e, se si dispone di relazioni circolari, sarà necessario rimuovere le chiavi esterne dallo schema e riapplicare dopo il trasferimento.In secondo luogo, LINQ-to-SQL non esegue un inserimento di identità, quindi se stai utilizzando colonne di identità a incremento automatico avrai problemi nell'invio. Non ho avuto successo nel forzare DataContext per abilitare l'inserimento dell'identità, ma YMMV.

+0

Forse una domanda sciocca, ma cos'è un DataContractCloner? Non riesco a trovare alcun riferimento nella documentazione ... –

+0

Sì, Google mostra esattamente un risultato: questa pagina! –

0

Si consiglia di prendere in considerazione l'utilizzo della classe SQLBulkCopy. È possibile trovare un articolo di progetto sul codice qui: http://www.codeproject.com/KB/database/SqlBulkCopy.aspx. Questo sarebbe un modo più rapido per farlo, ma suppongo che ti richiederà di creare le query tu stesso invece di lasciare che LINQ-to-SQL lo faccia.

3

Prova questa

using (DCDest = new DBDataContext(DestConnStr)) 
{ 
    DCDest.Customers.InsertOnSubmit(customer.ToList()); //note the use of .ToList() 
    DCDest.SubmitChanges(); 
} 
+0

Questo ha funzionato perfettamente per me. Grazie! –