Loupe

Import de données sur SQLServer

Dans une de mes nouvelles missions, je devais importer un fort volume de données dans une base de donnée SQLServer.

Chaque donnée “importée” devait ou être mise à jour si elle existait déjà, ou être créée si elle n’existait pas.

 

La première solution qui m’est venue à l’idée était de faire trois requêtes par données importée :

- la première en envoyant la liste d’Id que l’on veut importer (le serveur répondant ceux existant)

- la seconde pour les inserts

- la troisième pour les mises à jour

 

Or cette méthode a l’inconvénient de diviser l’import en 3 requêtes SQL différentes. Ce qui veut dire qu’on a la possibilité que le serveur SQL échoue à 3 endroits au lieu d’un et on a aussi 3 aller-retour avec ce serveur…

 

L’idéal est d’envoyer la liste complète des imports à la base en une seule requête SQL de données et que celle-ci les insère ou mette à jour directement.

SQLServer pouvant gérer des types complexes, on peut donc créer une procédure stockée permettant de faire le traitement en une seule fois.

 

Implémentation:

Pour ce faire il faut procéder en 3 étapes.

Il faut créer un TYPE SQLServer :

CREATE TYPE TalbetType AS TABLE 
( 
  Id uniqueidentifier NOT NULL,
  Name[nvarchar](MAX)NOT NULL,  
  ExternalId varchar(MAX) NOT NULL, 
  Type int NULL
);

 

Il faut créer la procédure stockée :

CREATE PROCEDURE [dbo].[SaveTablets]
(
    @Tablets [dbo].[TalbetType] READONLY
)
AS
BEGIN
    MERGE [dbo].[Tablets ] as target
    USING @Tablets AS source
    ON target.[ExternalId ] = source.[ExternalId]
    WHEN MATCHED THEN
    UPDATE SET target.[Id] = source.[Id],
    target.[ExternalId] = source.[ExternalId],
    target.[Name] = source.[Name],
    target.[Type] = source.[Type]
    WHEN NOT MATCHED THEN
    INSERT ([Id],[Name],[ExternalId],[Type])
    VALUES (source.[Id],source.[Name], source.[ExternalId], source.[Type]);
END

Et ensuite pour appeler la procédure stockée , il faut faire de la manière suivante :

            //Creation du datatable correspondant au type TabletType
            var dataTable = new DataTable("dt");
            dataTable.Columns.Add("Id", typeof(Guid));
            dataTable.Columns.Add("Name", typeof(string));
            dataTable.Columns.Add("ExternalId", typeof(string));
            dataTable.Columns.Add(new DataColumn("Type", typeof(int)) { AllowDBNull = true });        
            foreach (var tablet in tablets)
            {
                DataRow dataRow = dataTable.NewRow();
                dataRow["Id"] = tablet.Id;
                dataRow["Name"] = tablet.Name;
                dataRow["Email "] = tablet.Email;
                dataRow["ExternalId"] = tablet .ExternalId;
                if (tablet.Type.HasValue)
                    dataRow["Type"] = attendee.Type.Value;
                else
                    dataRow["Type"] = DBNull.Value;
                dataTable.Rows.Add(dataRow);
                dataRow.AcceptChanges();
            }
            //Création du parametre SQL
            var tableParameter = new SqlParameter("tablets", dataTable);
            tableParameter.TypeName = "TalbetType";
            tableParameter.SqlDbType = SqlDbType.Structured;
            //On execute la requête
            return await _context.Database.ExecuteSqlCommandAsync("SaveTablets @tablets", tableParameter);

 

 

Avantages:

Les avantages de cette méthode sont :

- on reste dans un mode fortement typé les données qu’on envoie à SQLServer ont un typage fort donc pas besoin de parser dans la procédure SQL pour récupérer les infos.

- tout l’import est réalisé en une seule requête SQL (donc un seul aller/retour).

Photo de profil

Ces billets pourraient aussi vous intéresser

Vous nous direz ?!

Commentaires

comments powered by Disqus