G
Guest
Having an expression that includes a relation reference causes GetChanges()
to fail with an exception. A simple Console program to demonstrate the
problem follows. Is this a known bug? Is there another/better workaround?
Thanks,
David
using System;
using System.Data;
using System.Collections;
namespace ConAppOverflow
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
// Create a dataset.
DataSet ds = new DataSet("ds");
DataTable dt1, dt2;
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
dt1 = new DataTable("DT1");
dt1.Columns.Add("ID", System.Type.GetType("System.Int32"));
dt1.Columns.Add("CAT", System.Type.GetType("System.Int32"));
dt1.Columns.Add("REF", System.Type.GetType("System.Int32"));
dt1.Columns.Add("Text", System.Type.GetType("System.String"));
ds.Tables.Add(dt1);
//Add relation for internal foreign key
dr = new DataRelation("DT1CAT2ID", dt1.Columns["ID"], dt1.Columns["CAT"]);
ds.Relations.Add(dr);
// Add some data
dt1.Rows.Add(new object[] {1,1,10, "One"});
dt1.Rows.Add(new object[] {2,1,20, "Two"});
dt1.Rows.Add(new object[] {3,1,30, "Three"});
dt2 = new DataTable("DT2");
dt2.Columns.Add("ID", System.Type.GetType("System.Int32"));
dt2.Columns.Add("CAT", System.Type.GetType("System.Int32"));
dt2.Columns.Add("REF", System.Type.GetType("System.Int32"));
dt2.Columns.Add("Text", System.Type.GetType("System.String"));
ds.Tables.Add(dt2);
//Add relation for internal foreign key
dr = new DataRelation("DT2CAT2ID", dt2.Columns["ID"], dt2.Columns["CAT"]);
ds.Relations.Add(dr);
//Add relation for external foreign key
dr = new DataRelation("DT2REF2DT1ID", dt1.Columns["ID"],
dt2.Columns["REF"]);
ds.Relations.Add(dr);
// And add one more computed column with reference to our parent relation
dt2.Columns.Add("RefText", System.Type.GetType("System.String"),
"Parent(DT2REF2DT1ID).Text");
// Add some data
dt2.Rows.Add(new object[] {10,10,1, "Ten"});
dt2.Rows.Add(new object[] {20,10,2, "Twenty"});
dt2.Rows.Add(new object[] {30,10,3, "Thirty"});
// And accept it
ds.Tables["DT1"].AcceptChanges();
ds.Tables["DT2"].AcceptChanges();
// now, edit a row and watch the stack flow... over.
DataRow drow = ds.Tables[0].Rows[0];
drow.BeginEdit();
drow["Text"] = "*" + drow["Text"];
drow.EndEdit();
bool doWorkAroundForStackOverFlow = true;
bool doWorkAroundForLookupNodeBind = false;
if (!doWorkAroundForStackOverFlow)
{
if (ds.HasChanges((DataRowState.Modified)))
{
DataSet xds = ds.GetChanges(DataRowState.Modified);
ds.AcceptChanges();
}
}
else
{
if (ds.HasChanges(DataRowState.Modified))
{
// We can't do a ds.GetChanges because of an ADO.NET bug with foreign
keys.
for (int iTbl = 0; iTbl < ds.Tables.Count; iTbl++)
{
if (!doWorkAroundForLookupNodeBind)
{
DataTable xdt = ds.Tables[iTbl].GetChanges(DataRowState.Modified);
if (xdt != null)
{
// ... work with the changes
ds.Tables[iTbl].AcceptChanges();
}
}
else
{
// And we can't do dt.GetChanges because of another ADO.NET bug with
expression columns.
// All computed columns with relations must be removed from the table
prior to GetChanges
// being called and then put back - ugh!
DataTable dtTemp;
DataTable dt = ds.Tables[iTbl];
ArrayList expressions = new ArrayList();
ArrayList indexes = new ArrayList();
for (int iCol = 0; iCol < dt.Columns.Count; iCol++)
{
// Just do all expressions - not just the ones involving relations
if (dt.Columns[iCol].Expression != null &&
dt.Columns[iCol].Expression != String.Empty)
{
expressions.Add(dt.Columns[iCol].Expression);
indexes.Add(iCol);
dt.Columns[iCol].Expression = string.Empty;
}
}
dtTemp = dt.GetChanges(DataRowState.Modified);
for (int index = 0; index < expressions.Count; index++)
{
int iCol = (int)indexes[index];
dt.Columns[iCol].Expression = (string) expressions[index];
}
if (dtTemp != null)
{
// ... work with the changes
dt.AcceptChanges();
}
}
}
}
}
Console.WriteLine("Normal Termination (press <ENTER>)");
Console.ReadLine();
}
}
}
to fail with an exception. A simple Console program to demonstrate the
problem follows. Is this a known bug? Is there another/better workaround?
Thanks,
David
using System;
using System.Data;
using System.Collections;
namespace ConAppOverflow
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
// Create a dataset.
DataSet ds = new DataSet("ds");
DataTable dt1, dt2;
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
dt1 = new DataTable("DT1");
dt1.Columns.Add("ID", System.Type.GetType("System.Int32"));
dt1.Columns.Add("CAT", System.Type.GetType("System.Int32"));
dt1.Columns.Add("REF", System.Type.GetType("System.Int32"));
dt1.Columns.Add("Text", System.Type.GetType("System.String"));
ds.Tables.Add(dt1);
//Add relation for internal foreign key
dr = new DataRelation("DT1CAT2ID", dt1.Columns["ID"], dt1.Columns["CAT"]);
ds.Relations.Add(dr);
// Add some data
dt1.Rows.Add(new object[] {1,1,10, "One"});
dt1.Rows.Add(new object[] {2,1,20, "Two"});
dt1.Rows.Add(new object[] {3,1,30, "Three"});
dt2 = new DataTable("DT2");
dt2.Columns.Add("ID", System.Type.GetType("System.Int32"));
dt2.Columns.Add("CAT", System.Type.GetType("System.Int32"));
dt2.Columns.Add("REF", System.Type.GetType("System.Int32"));
dt2.Columns.Add("Text", System.Type.GetType("System.String"));
ds.Tables.Add(dt2);
//Add relation for internal foreign key
dr = new DataRelation("DT2CAT2ID", dt2.Columns["ID"], dt2.Columns["CAT"]);
ds.Relations.Add(dr);
//Add relation for external foreign key
dr = new DataRelation("DT2REF2DT1ID", dt1.Columns["ID"],
dt2.Columns["REF"]);
ds.Relations.Add(dr);
// And add one more computed column with reference to our parent relation
dt2.Columns.Add("RefText", System.Type.GetType("System.String"),
"Parent(DT2REF2DT1ID).Text");
// Add some data
dt2.Rows.Add(new object[] {10,10,1, "Ten"});
dt2.Rows.Add(new object[] {20,10,2, "Twenty"});
dt2.Rows.Add(new object[] {30,10,3, "Thirty"});
// And accept it
ds.Tables["DT1"].AcceptChanges();
ds.Tables["DT2"].AcceptChanges();
// now, edit a row and watch the stack flow... over.
DataRow drow = ds.Tables[0].Rows[0];
drow.BeginEdit();
drow["Text"] = "*" + drow["Text"];
drow.EndEdit();
bool doWorkAroundForStackOverFlow = true;
bool doWorkAroundForLookupNodeBind = false;
if (!doWorkAroundForStackOverFlow)
{
if (ds.HasChanges((DataRowState.Modified)))
{
DataSet xds = ds.GetChanges(DataRowState.Modified);
ds.AcceptChanges();
}
}
else
{
if (ds.HasChanges(DataRowState.Modified))
{
// We can't do a ds.GetChanges because of an ADO.NET bug with foreign
keys.
for (int iTbl = 0; iTbl < ds.Tables.Count; iTbl++)
{
if (!doWorkAroundForLookupNodeBind)
{
DataTable xdt = ds.Tables[iTbl].GetChanges(DataRowState.Modified);
if (xdt != null)
{
// ... work with the changes
ds.Tables[iTbl].AcceptChanges();
}
}
else
{
// And we can't do dt.GetChanges because of another ADO.NET bug with
expression columns.
// All computed columns with relations must be removed from the table
prior to GetChanges
// being called and then put back - ugh!
DataTable dtTemp;
DataTable dt = ds.Tables[iTbl];
ArrayList expressions = new ArrayList();
ArrayList indexes = new ArrayList();
for (int iCol = 0; iCol < dt.Columns.Count; iCol++)
{
// Just do all expressions - not just the ones involving relations
if (dt.Columns[iCol].Expression != null &&
dt.Columns[iCol].Expression != String.Empty)
{
expressions.Add(dt.Columns[iCol].Expression);
indexes.Add(iCol);
dt.Columns[iCol].Expression = string.Empty;
}
}
dtTemp = dt.GetChanges(DataRowState.Modified);
for (int index = 0; index < expressions.Count; index++)
{
int iCol = (int)indexes[index];
dt.Columns[iCol].Expression = (string) expressions[index];
}
if (dtTemp != null)
{
// ... work with the changes
dt.AcceptChanges();
}
}
}
}
}
Console.WriteLine("Normal Termination (press <ENTER>)");
Console.ReadLine();
}
}
}