2009-05-15 5 views
9

Étant donné deux bases de données de schéma identique, existe-t-il un moyen simple de transférer des enregistrements entre les deux? J'utilise LINQ to SQL car j'ai besoin d'effectuer quelques opérations supplémentaires en cours de route et d'avoir des objets représentant les enregistrements que je transfère le rend beaucoup plus facile. Ceci est une application d'aide à petite échelle, donc SSIS est probablement overkill et SQLBulkCopy ne me permet pas d'interroger facilement les objets en cours de route.Utilisation de LINQ to SQL pour copier entre des bases de données

Ce que je voudrais faire est la suivante:

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

Mais pour des raisons évidentes, qui déclenche une exception avec le message:

Une tentative a été faite pour attacher ou Ajouter un entité qui n'est pas nouvelle, ayant peut-être été chargée depuis un autre DataContext. Ce n'est pas supporté.

Je peux contourner cela en faisant une copie superficielle de l'objet comme celui-ci:

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

puis insérer l'élément cloné. Si je ne fais que copier les champs en question, et non les références représentant les relations de table cela fonctionne très bien. C'est un peu long et la façon dont je le fais a besoin que j'attribue manuellement tous les champs de la méthode Clone. Quelqu'un pourrait-il suggérer des moyens de rendre cela plus facile? Les deux choses que je voudrais savoir sont:

  1. peut LINQ to SQL faire cela d'une manière plus facile,
  2. Y at-il un bon moyen d'utiliser la réflexion pour faire une copie peu profonde qui insérera?

Merci beaucoup!

Répondre

0

Est-ce purement un exercice académique?

Sinon je pense sérieusement à l'aide de SSIS: http://msdn.microsoft.com/en-us/library/ms141026.aspx au lieu, ou à défaut Rhino ETL. http://ayende.com/Blog/archive/2008/01/16/Rhino-ETL-2.0.aspxfor transférer des données entre les bases de données [texte du lien] [1]

+1

Ce qui est réel, mais il est seulement une application d'aide légère pour moi d'utiliser. Je ne prévois pas de transférer plus de 50 lignes sur plusieurs tables dans chaque lot, donc je pense que SSIS est probablement exagéré. Ma solution actuelle utilisant une méthode clone par objet fonctionne très bien, mais elle semble inélégante. J'ai besoin d'ajouter d'autres tables, donc je voulais trouver un meilleur moyen avant d'écrire plus de méthodes de clones! –

3

est ici un moyen d'objets LINQ clone peu profond (en omettant la clé primaire): Copy Linq Objects.

Il pourrait être modifié pour utiliser le méta-modèle si vous n'utilisez pas d'attributs. Ensuite, tout ce dont vous avez besoin est de 2 contextes de données (une source, une destination).

Sinon, vous pouvez regarder SqlBulkCopy - voir Copy from one database table to another C#

+0

C'est vraiment utile merci. J'utilise des classes d'entités générées automatiquement afin qu'elles aient toutes les balises dont j'ai besoin pour utiliser votre méthode clone. Il semble toujours que LINQ to SQL devrait faciliter cela, mais si personne ne sait comment le faire, cela me fera gagner beaucoup de temps. –

0

Pourquoi utiliser LINQ pour le faire? Il semble un peu inutile pour un framework de gêner quand vous pouvez utiliser le DTS de SQL Server.

+0

Vous n'avez même pas besoin de DTS; SqlBulkCopy fonctionnerait, et est d'environ 5 lignes de code. –

+0

Je dois être en mesure d'effectuer quelques opérations supplémentaires en cours de route - dans ce cas, avoir des classes d'entités me facilite la vie autrement ... Je sais que ce n'est pas la meilleure façon de transférer des disques mais il y en a d'autres facteurs qui me donnent envie d'utiliser LINQ. –

+0

Je pense que vous pouvez faire des choses personnalisées avec DTS. Je ne suis pas trop sûr de sa flexibilité. Je pense qu'il vaut la peine d'enquêter si vous ne trouvez pas de réponse ici. – uriDium

0

J'utilise le DataContractCloner pour détacher des entités LINQ to SQL:

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

Toutes les entités LINQ to SQL sont déjà annotées, donc cela crée un clone attachable que vous pouvez ensuite ré-attacher une quelques mises en garde. Tout d'abord, les relations de clés étrangères seront résolues, vous devez donc les insérer par ordre de dépendance, et si vous avez des relations circulaires, vous devrez supprimer les clés étrangères de votre schéma et réappliquer après le transfert.Deuxièmement, LINQ-to-SQL n'effectue pas d'insertion d'identité. Par conséquent, si vous utilisez des colonnes d'identité à incrémentation automatique, vous rencontrerez des problèmes lors de la soumission. Je n'ai pas réussi à forcer le DataContext à activer l'insertion d'identité, mais YMMV.

+0

Question idiote peut-être, mais qu'est-ce qu'un DataContractCloner? Je ne trouve aucune référence dans la documentation ... –

+0

Ouais - Google donne exactement un résultat: cette page! –

0

Vous pourriez envisager d'utiliser la classe SQLBulkCopy à la place. Vous pouvez trouver un article de projet de code à ce sujet ici: http://www.codeproject.com/KB/database/SqlBulkCopy.aspx. Ce serait une façon plus rapide de le faire, mais je suppose que cela vous demandera de créer vous-même les requêtes au lieu de laisser LINQ-to-SQL le faire.

3

Essayez cette

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

Cela a fonctionné parfaitement pour moi. Merci! –

Questions connexes