DataSet.GetChanges() -> StackOverflow in ShouldWriteRowAsUpdate()

G

Guest

The console application below demonstrates the problem. Is there a fix?

using System;
using System.Data;

namespace ConAppOverflow
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
// Create a dataset.
DataSet ds = new DataSet("ds");
DataTable dt;
DataRelation dr;

// Create two tables with [very] similar schema
// ID is the key
// CAT is an internal foreign key
// Ref is an external foreign key
// Text is text
dt = new DataTable("DT1");
dt.Columns.Add("ID", System.Type.GetType("System.Int32"));
dt.Columns.Add("CAT", System.Type.GetType("System.Int32"));
dt.Columns.Add("REF", System.Type.GetType("System.Int32"));
dt.Columns.Add("Text", System.Type.GetType("System.String"));
ds.Tables.Add(dt);

//Add relation for internal foreign key
dr = new DataRelation("DT1CAT2ID", dt.Columns["ID"], dt.Columns["CAT"]);
ds.Relations.Add(dr);

// Add some data
dt.Rows.Add(new object[] {1,1,10, ""});
dt.Rows.Add(new object[] {2,1,20, ""});
dt.Rows.Add(new object[] {3,1,30, ""});


dt = new DataTable("DT2");
dt.Columns.Add("ID", System.Type.GetType("System.Int32"));
dt.Columns.Add("CAT", System.Type.GetType("System.Int32"));
dt.Columns.Add("REF", System.Type.GetType("System.Int32"));
dt.Columns.Add("Text", System.Type.GetType("System.String"));
ds.Tables.Add(dt);

//Add relation for internal foreign key
dr = new DataRelation("DT2CAT2ID", dt.Columns["ID"], dt.Columns["CAT"]);
ds.Relations.Add(dr);

// Add some data
dt.Rows.Add(new object[] {10,10,1, ""});
dt.Rows.Add(new object[] {20,10,2, ""});
dt.Rows.Add(new object[] {30,10,3, ""});

// And accept it
ds.Tables["DT1"].AcceptChanges();
ds.Tables["DT2"].AcceptChanges();

// now, edit a row and watch the stack overflow...
DataRow drow = ds.Tables[0].Rows[0];
drow.BeginEdit();
drow["Text"] = "*" + drow["Text"];
drow.EndEdit();

if (ds.HasChanges((DataRowState.Modified)))
{
DataSet xds = ds.GetChanges(DataRowState.Modified);
ds.AcceptChanges();
}
}
}
}
 
G

Guest

I have a proposed workaround suggested by Shai Goldberg in "Subject: RE:
Constraint error when dataset.GetChanges() invoked", but I am not sure it
will not have side-effects:

Change the last block of code to:

if (ds.HasChanges((DataRowState.Modified)))
{
// We can't do a ds.GetChanges() because of an ADO.NET bug. So we
// do a GetChanges() on each table instead.

for (int i = 0; i < ds.Tables.Count; i++)
{
DataTable xdt = ds.Tables.GetChanges(DataRowState.Modified);
// ... work with the changes
ds.Tables.AcceptChanges();
}
}

David
 
G

Guest

(I wish we could edit. I hate talking to myself...) The code workaround had a
bug. It should read:

if (ds.HasChanges(DataRowState.Modified))
{
// We can't do a ds.GetChanges because of an ADO.NET bug.
for (int i = 0; i < ds.Tables.Count; i++)
{
DataTable xdt = ds.Tables.GetChanges(DataRowState.Modified);
if (xdt != null)
{
// ... work with the changes
ds.Tables.AcceptChanges();
}
}
}

David

David W. Rogers said:
I have a proposed workaround suggested by Shai Goldberg in "Subject: RE:
Constraint error when dataset.GetChanges() invoked", but I am not sure it
will not have side-effects:

Change the last block of code to:

if (ds.HasChanges((DataRowState.Modified)))
{
// We can't do a ds.GetChanges() because of an ADO.NET bug. So we
// do a GetChanges() on each table instead.

for (int i = 0; i < ds.Tables.Count; i++)
{
DataTable xdt = ds.Tables.GetChanges(DataRowState.Modified);
// ... work with the changes
ds.Tables.AcceptChanges();
}
}

David

David W. Rogers said:
The console application below demonstrates the problem. Is there a fix?

using System;
using System.Data;

namespace ConAppOverflow
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
// Create a dataset.
DataSet ds = new DataSet("ds");
DataTable dt;
DataRelation dr;

// Create two tables with [very] similar schema
// ID is the key
// CAT is an internal foreign key
// Ref is an external foreign key
// Text is text
dt = new DataTable("DT1");
dt.Columns.Add("ID", System.Type.GetType("System.Int32"));
dt.Columns.Add("CAT", System.Type.GetType("System.Int32"));
dt.Columns.Add("REF", System.Type.GetType("System.Int32"));
dt.Columns.Add("Text", System.Type.GetType("System.String"));
ds.Tables.Add(dt);

//Add relation for internal foreign key
dr = new DataRelation("DT1CAT2ID", dt.Columns["ID"], dt.Columns["CAT"]);
ds.Relations.Add(dr);

// Add some data
dt.Rows.Add(new object[] {1,1,10, ""});
dt.Rows.Add(new object[] {2,1,20, ""});
dt.Rows.Add(new object[] {3,1,30, ""});


dt = new DataTable("DT2");
dt.Columns.Add("ID", System.Type.GetType("System.Int32"));
dt.Columns.Add("CAT", System.Type.GetType("System.Int32"));
dt.Columns.Add("REF", System.Type.GetType("System.Int32"));
dt.Columns.Add("Text", System.Type.GetType("System.String"));
ds.Tables.Add(dt);

//Add relation for internal foreign key
dr = new DataRelation("DT2CAT2ID", dt.Columns["ID"], dt.Columns["CAT"]);
ds.Relations.Add(dr);

// Add some data
dt.Rows.Add(new object[] {10,10,1, ""});
dt.Rows.Add(new object[] {20,10,2, ""});
dt.Rows.Add(new object[] {30,10,3, ""});

// And accept it
ds.Tables["DT1"].AcceptChanges();
ds.Tables["DT2"].AcceptChanges();

// now, edit a row and watch the stack overflow...
DataRow drow = ds.Tables[0].Rows[0];
drow.BeginEdit();
drow["Text"] = "*" + drow["Text"];
drow.EndEdit();

if (ds.HasChanges((DataRowState.Modified)))
{
DataSet xds = ds.GetChanges(DataRowState.Modified);
ds.AcceptChanges();
}
}
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top