2009-09-08 14 views
2

J'ai un DataTable avec une colonne "Id", qui est une colonne d'identité dans notre base de données SQL Server 2005. Cette colonne a la propriété AutoIncrement définie sur true. Je ne remplis pas la table avec des données de la base de données, puisque je l'utilise uniquement pour les insertions, donc elle attribue des Ids fictifs à partir de 1.Comment faire pour mettre à jour toutes les colonnes autoincrement dans un DataTable?

Mais après avoir appelé la tableAdapter.Update(), je voudrais avoir dans cette colonne les ID REAL affectés par la base de données.

Pour une raison quelconque, seule la première ligne est mise à jour, et pas tout le reste. Cette table se référence elle-même à l'aide d'une DataRelation en cascade (structure hiérarchique) et les références à la première ligne sont également mises à jour.

Veuillez indiquer comment mettre tous les ID à jour en conséquence.

Merci d'avance!

instruction INSERT:

INSERT INTO Components (ComponentId, OrderNo, SerialNo) 
VALUES (@ComponentId, @OrderNo, @SerialNo) 

Et voici le schéma du tableau Composants:

Id BIGINT PK, 
ComponentId BIGINT FK, 
OrderNo int, 
SerialNo int 

Notez que le nom de colonne Id est "Id", "ComponentId" est la colonne de référence FK.

+0

Pouvez-vous publier votre instruction d'insertion qui appartient à la commande Insérer? – gsharp

+0

Sure: INSERT INTO Composants (ComponentId, OrderNo, SerialNo) VALEURS (@ ComponentId, @ OrderNo, @ SerialNo). Et voici le schéma de la table des composants: Id BIGINT PK, ComponentId BIGINT FK, OrderNo int, SerialNo int Notez que le nom de la colonne Id est "Id", "ComponentId" est la colonne de référence FK. –

Répondre

0

Le problème était dans le DataRelation mentionné. Pour une raison quelconque, en raison de cette DataRelation, les lignes "enfant" n'ont pas été insérées dans la base de données et leurs ID n'ont pas été mis à jour, bien que le contrôle "Rafraîchir la table de données" ait été activé dans DataTable). J'ai supprimé le DataRelation et j'ai fait tout le travail à la main. Le code suivant a fait l'affaire pour moi:

ComponentsTableAdapter cta = new ComponentsTableAdapter();      
foreach (UpdaterDataSet.ComponentsRow r in uds.Components.Rows) 
{      
    long origId = r.Id; 
    cta.Update(r); 

    foreach (UpdaterDataSet.ComponentsRow s in uds.Components.Rows) 
    { 
     if (s.Id != r.Id && !s.IsComponentIdNull() && s.ComponentId == origId) 
     s.ComponentId = r.Id; 
    }     
} 
+0

mais lorsque l'ensemble de données est configuré correctement, il n'y a pas besoin d'un tel "hack" .. – gsharp

+0

Oui, mais qu'est-ce qui ne va pas avec l'ensemble de données? Pourquoi ce comportement est-il possible en premier lieu? IMO, cela prouve juste la fuite de l'abstraction de l'ensemble de données. –

0

Avant l'exécution de remplissage méthode créer un DataColumn avec autoincrement,

EDIT:

SqlConnection cn = new SqlConnection(@"Connection_String"); 
    SqlDataAdapter adp; 
    SqlCommandBuilder cb; 
    DataTable dt; 

    private void Form3_Load(object sender, EventArgs e) 
    { 
     adp= new SqlDataAdapter("select * from temp", cn); 
     cb = new SqlCommandBuilder(adp); 
     dt = new DataTable(); 
     dt.Columns.Add("SrNo", typeof(int)); 
     dt.Columns[0].AutoIncrement = true; 
     dt.Columns[0].AutoIncrementSeed = 1; 
     dt.Columns[0].AutoIncrementStep = 1; 

     adp.Fill(dt); 
     dataGridView1.DataSource = dt; 
    } 
    private void button1_Click(object sender, EventArgs e) 
    { 
     adp.Update(dt); 
    } 
+0

Je n'appelle pas Fill, seulement Update. DataTable est utilisé uniquement pour les insertions. Mais après avoir appelé Update, j'ai besoin des vrais ID. –

0

Vous devez retourner l'identité de retour de SQL. Mais je ne suis pas sûr de la syntaxe exacte plus

Try

INSERT INTO Components (ComponentId, OrderNo, SerialNo) 
VALUES (@ComponentId, @OrderNo, @SerialNo); 
SET @ComponentId = SCOPE_IDENTITY() 

OU

INSERT INTO Components (ComponentId, OrderNo, SerialNo) 
VALUES (@ComponentId, @OrderNo, @SerialNo); 
SELECT SCOPE_IDENTITY() 
4

Cela était vraiment facile. Vous devez simplement définir les valeurs Column.AutoIncrementSeed et Column.AutoIncrementStep BOTH comme étant "-1". De cette façon, les nouvelles lignes qui ont été ajoutées auront des ID de -1, -2, et ainsi de suite. Ensuite, soit stocké ou votre code de procs TSQL seraient simplement:

UPDATE Table 
SET 
    Col1 = @Col1 
    Col2 = @Col2 
WHERE (ID = @ID) -- If this is -1, -2, etc, it won't update 

IF (@@ROWCOUNT = 0) 
    BEGIN 
    INSERT INTO Table(Col1, Col2) VALUES(Col1, Col2) 
    SET @ID = SCOPE_IDENTITY(); -- @ID would now change from -1 to 1, 2, 3, etc. 
END 

Cependant, Microsoft dans leur sagesse infinte changé tout cela pour le pire avec ADO.NET 4.0. Je ne suis pas vraiment sûr quand il a changé, mais ils ont un champ privé sous-jacent maintenant sur les colonnes AutoIncrement qui stocke la valeur actuelle de cette colonne à l'intérieur. Donc, disons dans la base de données, la dernière valeur insérée comme "52", bien, qui serait cachée dans la colonne AutoIncrement maintenant. Cela provoque des problèmes énormes avec les applications multi-utilisateurs maintenant et je ne peux plus utiliser le "-1" tour car il commence à compter à rebours de cette dernière valeur AutoIncrement.J'ai même essayé de recourir à la réflexion pour changer cela et ça ne sert à rien. Je déteste que Microsoft a cassé ceci dans ADO.NET et pourtant ils tiennent leur mantra de "Non, nous ne réparerons pas le bogue X [qui n'affectera pas vraiment les utilisateurs] mais nous mettrons en application quelque chose de complètement nouveau qui bousillera tout le code que vous avez jamais eu à travailler ".

Questions connexes