web-dev-qa-db-fra.com

SqlBulkCopy Insertion avec colonne d'identité

J'utilise l'objet SqlBulkCopy pour insérer quelques millions de lignes générées dans une base de données. Le seul problème est que la table dans laquelle j'insère a une colonne d'identité. J'ai essayé de définir SqlBulkCopyOptions sur SqlBulkCopyOptions.KeepIdentity et de définir la colonne identité sur 0 ', DbNull.Value et null. Aucun d'entre eux ont fonctionné. J'ai l'impression de rater quelque chose d'assez simple, si quelqu'un pouvait m'éclairer, ce serait fantastique. Merci!

edit Pour clarifier, je n’ai pas les valeurs d’identité définies dans la variable DataTable que j’importe. Je veux qu'ils soient générés dans le cadre de l'importation.

éditez 2 Voici le code que j'utilise pour créer l'objet SqlBulkCopy de base.

SqlBulkCopy sbc = GetBulkCopy(SqlBulkCopyOptions.KeepIdentity);
sbc.DestinationTableName = LOOKUP_TABLE;

private static SqlBulkCopy GetBulkCopy(SqlBulkCopyOptions options = 
    SqlBulkCopyOptions.Default) 
{
    Configuration cfg = WebConfigurationManager.OpenWebConfiguration("/RSWifi");
    string connString =
    cfg.ConnectionStrings.ConnectionStrings["WifiData"].ConnectionString;
    return new SqlBulkCopy(connString, options);
}
56
FlyingStreudel

Pour que la table de destination attribue l'identité, n'utilisez pas l'option SqlBulkCopyOptions.KeepIdentity. Au lieu de cela, ne mappez pas l'identité de la source et ne l'extrayez pas de la source pour l'envoyer à SqlBulkCopy.

34
jason

Remplissez la ColumnMapping de l'objet BulkCopy et ne mappez pas la colonne d'identité. La colonne d'identité sera générée par la base de données cible.

21
Wim

Oui, vous avez raison d'utiliser l'option SqlBulkCopyOptions.KeepIdentity, alors le rédacteur en bloc ne pense pas que la structure de la table de cet objet soit écrite à partir de la colonne de démarrage. créez une colonne supplémentaire dans votre objet datatable avec le reste de vos colonnes nécessaires et transmettez des valeurs null à cette colonne, puis la table gère automatiquement l'identité.

1
user2522747

Vous avez deux options -

1 - utilisez KeepIdentity et conservez les valeurs Identity de la source.

2 - Ne mappez pas le champ Identity. Si vous n'essayez pas d'attribuer une valeur, la table cible en affectera une automatiquement.

1
JNK

C'est la table

CREATE TABLE [dbo].[ProductShippingMethodMap](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [ProductId] [int] NOT NULL,
    [ShippingMethodId] [int] NOT NULL,
    [ParentProductId] [int] NOT NULL,
 CONSTRAINT [PK_ProductShippingMethodMap] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

Le code C # ci-dessous fonctionne

 DataTable dtQtyData = new DataTable();
        dtQtyData.Clear();
        dtQtyData.Columns.Add("Id", typeof(int));

    dtQtyData.Columns.Add("ProductId", typeof(int));
    dtQtyData.Columns.Add("ShippingMethodId", typeof(int));
    dtQtyData.Columns.Add("ParentProductId", typeof(int));


    for (int i = 0; i < ShippingMethodIds.Length; i++)
    {
        for (int j = 0; j < ProductIds.Length; j++)
        {
            var productId = ProductIds[j];
            var shippingMethodId = ShippingMethodIds[i];
            dtQtyData.Rows.Add(new object[] {0,productId, shippingMethodId, parentProductId });
        }

    }
    var connectionString = new DataSettingsManager().LoadSettings().DataConnectionString;
    SqlBulkCopy bulkcopy = new SqlBulkCopy(connectionString, SqlBulkCopyOptions.Default);
    bulkcopy.DestinationTableName = "ProductShippingMethodMap";
    bulkcopy.WriteToServer(dtQtyData);
0
sina_Islam

Voici comment je l'ai résolu dans .NET Core (dt est votre datatable):

dt.Columns.Cast<DataColumn>().ForEach((c, i) => sqlBulkCopy.ColumnMappings.Add(c.ColumnName, i + 1));

En gros, vous sautez la colonne d'identité (Id) en affectant à vos colonnes de destination un ordinal commençant par 1 au lieu de 0.

0
silkfire