DataRowView Equals does not work as documented

  • Thread starter Thread starter Grant Frisken
  • Start date Start date
G

Grant Frisken

I have an application where I have two different DataViews of the same
DataTable displayed in separate DataGrids (potentially sorted or filtered
differently). I would like to be able to link the selection between the two
grids so that when a row is selected in one the corresponding row is
selected in the other.

To do this I get the DataRowView at the selected index in the first DataView
and then attempt to find the index of this DataRowView within the second
DataView using the DataView IList interface IndexOf method. The IndexOf
method works perfectly if the DataRowView came from this DataView - however
if fails (always returns -1) if the DataRowView comes from a different
DataView.

The DataRowView.Equals documentation says:

Return Value
true, if object is a DataRowView and it returns the same row as the
current DataRowView; otherwise, false.

So I would have expected that IndexOf should have worked in both cases
presuming that it was using the Equals method to compare DataRowViews.
This prompted me to check whether the DataRowView Equals method actually was
doing what the documentation said. It appears not to be. The code below
using the standard Northwind database illustrates the problem.

Any insight would be appreciated


// Setup the dataset
//
DataSet ds = new DataSet();
string connection = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=northwind.mdb";
System.Data.OleDb.OleDbDataAdapter dbAdapter = new
System.Data.OleDb.OleDbDataAdapter("SELECT * FROM Customers", connection);
dbAdapter.Fill(ds, "Customers");

// create the first data view
//
DataViewManager dvm = new DataViewManager(ds);
DataView view1 = dvm.CreateDataView(ds.Tables["Customers"]);

// find an arbitrary row
//
view1.Sort = "CustomerID";
DataRowView rv1 = view1[view1.Find("ALFKI")];

// check that IndexOf works OK (it does)
//
int index1 = ((IList)view1).IndexOf(rv1);

// create a second data view
//
DataView view2 = dvm.CreateDataView(ds.Tables["Customers"]);

// try to find the index of the row we found earlier in this DataView
(doesn't work)
//
int index2 = ((IList)view2).IndexOf(rv1);

// OK lets see if we retrieve the same row from the 2nd data view whether
Equals works as advertised
//
view2.Sort = "CustomerID";
DataRowView rv2 = view2[view2.Find("ALFKI")];

if (rv1.Row == rv2.Row)
Debug.WriteLine("Row Equal"); // the row is equal alright
else
Debug.WriteLine("Row Not Equal");
if (rv1.Equals(rv2))
Debug.WriteLine("View Equal");
else
Debug.WriteLine("View Not Equal"); // but the DataRowView is not
Equal so we end up here why?
 
Hi Grant,

This is normal behaviour.
DataRowView is compared by reference I assume thus you won't find it in
another DataView.
You should compare the rowviews by primary key instead.

HTH,
--
Miha Markic [MVP C#] - RightHand .NET consulting & software development
miha at rthand com
www.rthand.com

Grant Frisken said:
I have an application where I have two different DataViews of the same
DataTable displayed in separate DataGrids (potentially sorted or filtered
differently). I would like to be able to link the selection between the two
grids so that when a row is selected in one the corresponding row is
selected in the other.

To do this I get the DataRowView at the selected index in the first DataView
and then attempt to find the index of this DataRowView within the second
DataView using the DataView IList interface IndexOf method. The IndexOf
method works perfectly if the DataRowView came from this DataView - however
if fails (always returns -1) if the DataRowView comes from a different
DataView.

The DataRowView.Equals documentation says:

Return Value
true, if object is a DataRowView and it returns the same row as the
current DataRowView; otherwise, false.

So I would have expected that IndexOf should have worked in both cases
presuming that it was using the Equals method to compare DataRowViews.
This prompted me to check whether the DataRowView Equals method actually was
doing what the documentation said. It appears not to be. The code below
using the standard Northwind database illustrates the problem.

Any insight would be appreciated


// Setup the dataset
//
DataSet ds = new DataSet();
string connection = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=northwind.mdb";
System.Data.OleDb.OleDbDataAdapter dbAdapter = new
System.Data.OleDb.OleDbDataAdapter("SELECT * FROM Customers", connection);
dbAdapter.Fill(ds, "Customers");

// create the first data view
//
DataViewManager dvm = new DataViewManager(ds);
DataView view1 = dvm.CreateDataView(ds.Tables["Customers"]);

// find an arbitrary row
//
view1.Sort = "CustomerID";
DataRowView rv1 = view1[view1.Find("ALFKI")];

// check that IndexOf works OK (it does)
//
int index1 = ((IList)view1).IndexOf(rv1);

// create a second data view
//
DataView view2 = dvm.CreateDataView(ds.Tables["Customers"]);

// try to find the index of the row we found earlier in this DataView
(doesn't work)
//
int index2 = ((IList)view2).IndexOf(rv1);

// OK lets see if we retrieve the same row from the 2nd data view whether
Equals works as advertised
//
view2.Sort = "CustomerID";
DataRowView rv2 = view2[view2.Find("ALFKI")];

if (rv1.Row == rv2.Row)
Debug.WriteLine("Row Equal"); // the row is equal alright
else
Debug.WriteLine("Row Not Equal");
if (rv1.Equals(rv2))
Debug.WriteLine("View Equal");
else
Debug.WriteLine("View Not Equal"); // but the DataRowView is not
Equal so we end up here why?
 
I am not comparing references. I didn't write:

if (rv1 == rv2)
{...

But

if (rv1.Equals(rv2))
{...

I understand that rv1 and rv2 are likely to be different objects and so
comparing their references will return false. But the "Equals" method for
DataRowView is documented as comparing the underlying row (which is actually
the same for both rv1 and rv2). Unfortunately it doesn't seem to do this.

Grant

Miha Markic said:
Hi Grant,

This is normal behaviour.
DataRowView is compared by reference I assume thus you won't find it in
another DataView.
You should compare the rowviews by primary key instead.

HTH,
--
Miha Markic [MVP C#] - RightHand .NET consulting & software development
miha at rthand com
www.rthand.com

Grant Frisken said:
I have an application where I have two different DataViews of the same
DataTable displayed in separate DataGrids (potentially sorted or filtered
differently). I would like to be able to link the selection between the two
grids so that when a row is selected in one the corresponding row is
selected in the other.

To do this I get the DataRowView at the selected index in the first DataView
and then attempt to find the index of this DataRowView within the second
DataView using the DataView IList interface IndexOf method. The IndexOf
method works perfectly if the DataRowView came from this DataView - however
if fails (always returns -1) if the DataRowView comes from a different
DataView.

The DataRowView.Equals documentation says:

Return Value
true, if object is a DataRowView and it returns the same row as the
current DataRowView; otherwise, false.

So I would have expected that IndexOf should have worked in both cases
presuming that it was using the Equals method to compare DataRowViews.
This prompted me to check whether the DataRowView Equals method actually was
doing what the documentation said. It appears not to be. The code below
using the standard Northwind database illustrates the problem.

Any insight would be appreciated


// Setup the dataset
//
DataSet ds = new DataSet();
string connection = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=northwind.mdb";
System.Data.OleDb.OleDbDataAdapter dbAdapter = new
System.Data.OleDb.OleDbDataAdapter("SELECT * FROM Customers", connection);
dbAdapter.Fill(ds, "Customers");

// create the first data view
//
DataViewManager dvm = new DataViewManager(ds);
DataView view1 = dvm.CreateDataView(ds.Tables["Customers"]);

// find an arbitrary row
//
view1.Sort = "CustomerID";
DataRowView rv1 = view1[view1.Find("ALFKI")];

// check that IndexOf works OK (it does)
//
int index1 = ((IList)view1).IndexOf(rv1);

// create a second data view
//
DataView view2 = dvm.CreateDataView(ds.Tables["Customers"]);

// try to find the index of the row we found earlier in this DataView
(doesn't work)
//
int index2 = ((IList)view2).IndexOf(rv1);

// OK lets see if we retrieve the same row from the 2nd data view whether
Equals works as advertised
//
view2.Sort = "CustomerID";
DataRowView rv2 = view2[view2.Find("ALFKI")];

if (rv1.Row == rv2.Row)
Debug.WriteLine("Row Equal"); // the row is equal alright
else
Debug.WriteLine("Row Not Equal");
if (rv1.Equals(rv2))
Debug.WriteLine("View Equal");
else
Debug.WriteLine("View Not Equal"); // but the DataRowView is not
Equal so we end up here why?
 
You are right, the code does an additional reference check against the
underlying DataViews after the DataRow reference check.


Grant Frisken said:
I am not comparing references. I didn't write:

if (rv1 == rv2)
{...

But

if (rv1.Equals(rv2))
{...

I understand that rv1 and rv2 are likely to be different objects and so
comparing their references will return false. But the "Equals" method for
DataRowView is documented as comparing the underlying row (which is actually
the same for both rv1 and rv2). Unfortunately it doesn't seem to do this.

Grant

Miha Markic said:
Hi Grant,

This is normal behaviour.
DataRowView is compared by reference I assume thus you won't find it in
another DataView.
You should compare the rowviews by primary key instead.

HTH,
--
Miha Markic [MVP C#] - RightHand .NET consulting & software development
miha at rthand com
www.rthand.com

Grant Frisken said:
I have an application where I have two different DataViews of the same
DataTable displayed in separate DataGrids (potentially sorted or filtered
differently). I would like to be able to link the selection between
the
two
grids so that when a row is selected in one the corresponding row is
selected in the other.

To do this I get the DataRowView at the selected index in the first DataView
and then attempt to find the index of this DataRowView within the second
DataView using the DataView IList interface IndexOf method. The IndexOf
method works perfectly if the DataRowView came from this DataView - however
if fails (always returns -1) if the DataRowView comes from a different
DataView.

The DataRowView.Equals documentation says:

Return Value
true, if object is a DataRowView and it returns the same row as the
current DataRowView; otherwise, false.

So I would have expected that IndexOf should have worked in both cases
presuming that it was using the Equals method to compare DataRowViews.
This prompted me to check whether the DataRowView Equals method
actually
was
doing what the documentation said. It appears not to be. The code below
using the standard Northwind database illustrates the problem.

Any insight would be appreciated


// Setup the dataset
//
DataSet ds = new DataSet();
string connection = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=northwind.mdb";
System.Data.OleDb.OleDbDataAdapter dbAdapter = new
System.Data.OleDb.OleDbDataAdapter("SELECT * FROM Customers", connection);
dbAdapter.Fill(ds, "Customers");

// create the first data view
//
DataViewManager dvm = new DataViewManager(ds);
DataView view1 = dvm.CreateDataView(ds.Tables["Customers"]);

// find an arbitrary row
//
view1.Sort = "CustomerID";
DataRowView rv1 = view1[view1.Find("ALFKI")];

// check that IndexOf works OK (it does)
//
int index1 = ((IList)view1).IndexOf(rv1);

// create a second data view
//
DataView view2 = dvm.CreateDataView(ds.Tables["Customers"]);

// try to find the index of the row we found earlier in this DataView
(doesn't work)
//
int index2 = ((IList)view2).IndexOf(rv1);

// OK lets see if we retrieve the same row from the 2nd data view whether
Equals works as advertised
//
view2.Sort = "CustomerID";
DataRowView rv2 = view2[view2.Find("ALFKI")];

if (rv1.Row == rv2.Row)
Debug.WriteLine("Row Equal"); // the row is equal alright
else
Debug.WriteLine("Row Not Equal");
if (rv1.Equals(rv2))
Debug.WriteLine("View Equal");
else
Debug.WriteLine("View Not Equal"); // but the DataRowView is not
Equal so we end up here why?
 
Hi Grant,

Ah, I see.
Unfortuantelly, Equals requires that the both DataRowViews belong to the
same DataView instance.
As a workaround you might do:
bool equal = rv1.Row == rv2.Row

--
Miha Markic [MVP C#] - RightHand .NET consulting & development
miha at rthand com
www.rthand.com

Grant Frisken said:
I am not comparing references. I didn't write:

if (rv1 == rv2)
{...

But

if (rv1.Equals(rv2))
{...

I understand that rv1 and rv2 are likely to be different objects and so
comparing their references will return false. But the "Equals" method for
DataRowView is documented as comparing the underlying row (which is actually
the same for both rv1 and rv2). Unfortunately it doesn't seem to do this.

Grant

Miha Markic said:
Hi Grant,

This is normal behaviour.
DataRowView is compared by reference I assume thus you won't find it in
another DataView.
You should compare the rowviews by primary key instead.

HTH,
--
Miha Markic [MVP C#] - RightHand .NET consulting & software development
miha at rthand com
www.rthand.com

Grant Frisken said:
I have an application where I have two different DataViews of the same
DataTable displayed in separate DataGrids (potentially sorted or filtered
differently). I would like to be able to link the selection between
the
two
grids so that when a row is selected in one the corresponding row is
selected in the other.

To do this I get the DataRowView at the selected index in the first DataView
and then attempt to find the index of this DataRowView within the second
DataView using the DataView IList interface IndexOf method. The IndexOf
method works perfectly if the DataRowView came from this DataView - however
if fails (always returns -1) if the DataRowView comes from a different
DataView.

The DataRowView.Equals documentation says:

Return Value
true, if object is a DataRowView and it returns the same row as the
current DataRowView; otherwise, false.

So I would have expected that IndexOf should have worked in both cases
presuming that it was using the Equals method to compare DataRowViews.
This prompted me to check whether the DataRowView Equals method
actually
was
doing what the documentation said. It appears not to be. The code below
using the standard Northwind database illustrates the problem.

Any insight would be appreciated


// Setup the dataset
//
DataSet ds = new DataSet();
string connection = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=northwind.mdb";
System.Data.OleDb.OleDbDataAdapter dbAdapter = new
System.Data.OleDb.OleDbDataAdapter("SELECT * FROM Customers", connection);
dbAdapter.Fill(ds, "Customers");

// create the first data view
//
DataViewManager dvm = new DataViewManager(ds);
DataView view1 = dvm.CreateDataView(ds.Tables["Customers"]);

// find an arbitrary row
//
view1.Sort = "CustomerID";
DataRowView rv1 = view1[view1.Find("ALFKI")];

// check that IndexOf works OK (it does)
//
int index1 = ((IList)view1).IndexOf(rv1);

// create a second data view
//
DataView view2 = dvm.CreateDataView(ds.Tables["Customers"]);

// try to find the index of the row we found earlier in this DataView
(doesn't work)
//
int index2 = ((IList)view2).IndexOf(rv1);

// OK lets see if we retrieve the same row from the 2nd data view whether
Equals works as advertised
//
view2.Sort = "CustomerID";
DataRowView rv2 = view2[view2.Find("ALFKI")];

if (rv1.Row == rv2.Row)
Debug.WriteLine("Row Equal"); // the row is equal alright
else
Debug.WriteLine("Row Not Equal");
if (rv1.Equals(rv2))
Debug.WriteLine("View Equal");
else
Debug.WriteLine("View Not Equal"); // but the DataRowView is not
Equal so we end up here why?
 
This is what I suspected - although not what the documentation says.
Unfortunately this means that I can not use the DataView IndexOf function to
find a given row. It would appear the only way to do this is to loop
through the DataView rows myself looking for rv1.Row == rv2.Row. I had a
hope that IndexOf may have been implemented more efficiently then this
(although it probably wasn't).

I am also writing a control which implements databinding via the IList
interface. It makes use of the IndexOf method to locate the position of a
selected item within the list (allowing the client to deal with domain
objects instead of list indices which may change if the list is sorted
differently). Unfortunately this inconsistency in the way DataView
implements IList means that I will probably have to deal with DataViews as a
special case.

Grant

Miha Markic said:
Hi Grant,

Ah, I see.
Unfortuantelly, Equals requires that the both DataRowViews belong to the
same DataView instance.
As a workaround you might do:
bool equal = rv1.Row == rv2.Row

--
Miha Markic [MVP C#] - RightHand .NET consulting & development
miha at rthand com
www.rthand.com

Grant Frisken said:
I am not comparing references. I didn't write:

if (rv1 == rv2)
{...

But

if (rv1.Equals(rv2))
{...

I understand that rv1 and rv2 are likely to be different objects and so
comparing their references will return false. But the "Equals" method for
DataRowView is documented as comparing the underlying row (which is actually
the same for both rv1 and rv2). Unfortunately it doesn't seem to do this.

Grant

Miha Markic said:
Hi Grant,

This is normal behaviour.
DataRowView is compared by reference I assume thus you won't find it in
another DataView.
You should compare the rowviews by primary key instead.

HTH,
--
Miha Markic [MVP C#] - RightHand .NET consulting & software development
miha at rthand com
www.rthand.com

I have an application where I have two different DataViews of the same
DataTable displayed in separate DataGrids (potentially sorted or filtered
differently). I would like to be able to link the selection between the
two
grids so that when a row is selected in one the corresponding row is
selected in the other.

To do this I get the DataRowView at the selected index in the first
DataView
and then attempt to find the index of this DataRowView within the second
DataView using the DataView IList interface IndexOf method. The IndexOf
method works perfectly if the DataRowView came from this DataView -
however
if fails (always returns -1) if the DataRowView comes from a different
DataView.

The DataRowView.Equals documentation says:

Return Value
true, if object is a DataRowView and it returns the same row as the
current DataRowView; otherwise, false.

So I would have expected that IndexOf should have worked in both cases
presuming that it was using the Equals method to compare DataRowViews.
This prompted me to check whether the DataRowView Equals method actually
was
doing what the documentation said. It appears not to be. The code below
using the standard Northwind database illustrates the problem.

Any insight would be appreciated


// Setup the dataset
//
DataSet ds = new DataSet();
string connection = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=northwind.mdb";
System.Data.OleDb.OleDbDataAdapter dbAdapter = new
System.Data.OleDb.OleDbDataAdapter("SELECT * FROM Customers", connection);
dbAdapter.Fill(ds, "Customers");

// create the first data view
//
DataViewManager dvm = new DataViewManager(ds);
DataView view1 = dvm.CreateDataView(ds.Tables["Customers"]);

// find an arbitrary row
//
view1.Sort = "CustomerID";
DataRowView rv1 = view1[view1.Find("ALFKI")];

// check that IndexOf works OK (it does)
//
int index1 = ((IList)view1).IndexOf(rv1);

// create a second data view
//
DataView view2 = dvm.CreateDataView(ds.Tables["Customers"]);

// try to find the index of the row we found earlier in this DataView
(doesn't work)
//
int index2 = ((IList)view2).IndexOf(rv1);

// OK lets see if we retrieve the same row from the 2nd data view whether
Equals works as advertised
//
view2.Sort = "CustomerID";
DataRowView rv2 = view2[view2.Find("ALFKI")];

if (rv1.Row == rv2.Row)
Debug.WriteLine("Row Equal"); // the row is equal alright
else
Debug.WriteLine("Row Not Equal");
if (rv1.Equals(rv2))
Debug.WriteLine("View Equal");
else
Debug.WriteLine("View Not Equal"); // but the DataRowView is not
Equal so we end up here why?
 
Back
Top