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);
}
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
.
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.
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é.
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.
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);
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.