DataView.Find not working with GUID

W

Warren J. Hairston

Using .NET 2.0, I have a DataView with two columns: JobID (a GUID) and
JobNumber (an integer). DataView.Sort = "JobID".

When I perform a DataView.Find(SomeJobID), I always get a result indicating
the row was found, but it's the wrong row (code below). In the code below,
as long as JobID is a valid GUID, the Offset is always the wrong row.

This code seems to fail only when the DataView.Sort is a GUID - works fine
on other types of data.

Any ideas? Is this a bug in .NET 2.0? I've seen this same problem described
elsewhere on the Internet, but no responses or answers.

Thanks in advance,
Warren

Offset = DV.Find(JobID);

if (Offset > -1)

{

JobNumberText = DV[Offset]["JobNumber"].ToString();

} //JobID was located
 
D

Dave Sexton

Hi,

I can't repro. Here's the code I used:

DataSet data = new DataSet();
DataTable table = data.Tables.Add();
table.Columns.Add("JobID", typeof(Guid));
table.Columns.Add("JobNumber", typeof(int));

table.Rows.Add(Guid.NewGuid(), 1);
table.Rows.Add(Guid.NewGuid(), 2);
table.Rows.Add(Guid.NewGuid(), 3);
table.Rows.Add(Guid.NewGuid(), 4);
DataRow searchRow = table.Rows.Add(Guid.NewGuid(), 5);

table.DefaultView.Sort = "JobID";

int index = table.DefaultView.Find(searchRow["JobID"]);

MessageBox.Show(index.ToString());


The output is always a random number from 0 to 4.

What have I done differently?
 
W

Warren J. Hairston

Dave,

It sounds like you ARE reproducing the problem. You say your output is
always a RANDOM number from 0 to 4 - that's exactly the problem - it's a
RANDOM number. I would expect that your code would always print "4" as the
output, since that's the offset where the value you're seeking resides.

- Warren
 
M

Miha Markic [MVP C#]

Looks fine to me. Enhanced code:
DataSet data = new DataSet();
DataTable table = data.Tables.Add();
table.Columns.Add("JobID", typeof(Guid));
table.Columns.Add("JobNumber", typeof(int));

table.Rows.Add(Guid.NewGuid(), 1);
table.Rows.Add(Guid.NewGuid(), 2);
table.Rows.Add(Guid.NewGuid(), 3);
table.Rows.Add(Guid.NewGuid(), 4);
DataRow searchRow = table.Rows.Add(Guid.NewGuid(), 5);

table.DefaultView.Sort = "JobID";

int index = table.DefaultView.Find(searchRow["JobID"]);

MessageBox.Show(
string.Format("index={0}, search={1} found={2} id={3}",
index, searchRow["JobID"],
table.DefaultView[index].Row["JobNumber"],
table.DefaultView[index].Row["JobID"]));
 
D

Dave Sexton

Hi Warren,

Guid.NewGuid() doesn't provide values in a sequence. The values produced
are "random", for all intensive purposes.

My code doesn't return -1, however, which is what I assumed your code was
returning. -1 would certainly be invalid since the last Guid that I added
is obviously in the DataTable. But since the DataView was sorted by the
Guid column, its sorted placement is indeterminate. Any value between 0 and
4 in my example is acceptable.
 
D

Dave Sexton

Hi Warren,

On a somewhat interesting side note, I looked up "for all intensive
purposes" because it just didn't look right to me - and it turns out that
it's not right :)

I meant to say, "to all intents and purposes". Apparently, this is a common
misunderstanding in the English language, so I don't feel too bad (although
maybe I should given that it's the only language I know :p)
 
W

Warren J. Hairston

Dave,

Thanks for the reply. My code isn't returning -1. Quite the contrary - it's
just that the answer isn't correct.

To make matters more interesting, I wrote a small test program wherein I
bound the DataView to a combo box and changed my query so that only 2 rows
were returned in the DataView. I bound the combo box DisplayMember to the
JobNumber field and the ValueMember to the JobID field. When I get the
SelectedValue, it's still wrong. This is similar to what I'm doing in my
program, so I think this is where the problem really lies. I can step
through with the debugger and see the contents of the combo box, but no
matter which combo box entry I select, the SelectedValue indicates that the
other value was selected.

In the code below, JobNumber and JobName should hold the same values at the
end of execution:


.... //a query to populate DV (the DataView) - debugger shows everything is
OK to this point
//cbOpenJobs is a combo box in a Windows Form - bind the DV to the combo box

DV.Sort = "JobID";

cbOpenJobs.DataSource = DV;

cbOpenJobs.DisplayMember = "JobNumber";

cbOpenJobs.ValueMember = "JobID";

.... //code below executes after the user selects a value
JobID = new Guid(cbOpenJobs.SelectedValue.ToString()); //ERROR - the value
returned is not the JobID of the record I selected from the combo box - it's
the JobID of the OTHER record!?!?
JobName = cbOpenJobs.Text; //this IS correct - the JobNumber of the record
I selected from the combo box

Offset = DV.Find(JobID);

if (Offset > -1)

{

JobNumber = DV[Offset]["JobNumber"].ToString(); //this always executes,
but because JobID was incorrect, the end result is that the wrong JobNumber
is selected here

} //JobID was located

else

{

JobNumber = "";

} //JobID was not located

//by the time we get here, JobNumber and JobName (which should hold the same
value) are different



Any insight will be greatly appreciated. Thanks in advance.
- Warren

P.S.: I was aware of the "intents and purposes" phrase - that's one of my
pet peeves. Another one that I'm seeing far too often is the phrase "I
should of done that..." for "I should've [should have] done that..." LOL -
funny how we can (usually) write working programs in other languages, but
have problems with our own. If the world was a compiler, I guess we'd never
be able to communicate because of syntax errors. :)
 
D

Dave Sexton

Hi Warren,

You must set the DataSource property after setting DisplayMember and
ValueMember otherwise the SelectedValue property will return a DataRowView,
not a Guid. Once you make this modification, you don't need to do the
following:
JobID = new Guid(cbOpenJobs.SelectedValue.ToString());

instead, just cast:

Guid jobID = (Guid) cbOpenJobs.SelectedValue;

I tested your solution with the changes above and everything worked just
fine. If you're still having problems getting the correct Guid from the
current selection then you may want to post a short but complete program, a
la Jon Skeet's article: http://www.yoda.arachsys.com/csharp/complete.html.

--
Dave Sexton

Warren J. Hairston said:
Dave,

Thanks for the reply. My code isn't returning -1. Quite the contrary -
it's just that the answer isn't correct.

To make matters more interesting, I wrote a small test program wherein I
bound the DataView to a combo box and changed my query so that only 2 rows
were returned in the DataView. I bound the combo box DisplayMember to the
JobNumber field and the ValueMember to the JobID field. When I get the
SelectedValue, it's still wrong. This is similar to what I'm doing in my
program, so I think this is where the problem really lies. I can step
through with the debugger and see the contents of the combo box, but no
matter which combo box entry I select, the SelectedValue indicates that
the other value was selected.

In the code below, JobNumber and JobName should hold the same values at
the end of execution:


... //a query to populate DV (the DataView) - debugger shows everything
is OK to this point
//cbOpenJobs is a combo box in a Windows Form - bind the DV to the combo
box

DV.Sort = "JobID";

cbOpenJobs.DataSource = DV;

cbOpenJobs.DisplayMember = "JobNumber";

cbOpenJobs.ValueMember = "JobID";

... //code below executes after the user selects a value
JobID = new Guid(cbOpenJobs.SelectedValue.ToString()); //ERROR - the
value returned is not the JobID of the record I selected from the combo
box - it's the JobID of the OTHER record!?!?
JobName = cbOpenJobs.Text; //this IS correct - the JobNumber of the
record I selected from the combo box

Offset = DV.Find(JobID);

if (Offset > -1)

{

JobNumber = DV[Offset]["JobNumber"].ToString(); //this always executes,
but because JobID was incorrect, the end result is that the wrong
JobNumber is selected here

} //JobID was located

else

{

JobNumber = "";

} //JobID was not located

//by the time we get here, JobNumber and JobName (which should hold the
same value) are different



Any insight will be greatly appreciated. Thanks in advance.
- Warren

P.S.: I was aware of the "intents and purposes" phrase - that's one of my
pet peeves. Another one that I'm seeing far too often is the phrase "I
should of done that..." for "I should've [should have] done that..." LOL -
funny how we can (usually) write working programs in other languages, but
have problems with our own. If the world was a compiler, I guess we'd
never be able to communicate because of syntax errors. :)
 
C

Chris Bordeman

for all intensive purposes.

You mean for all intents and purposes? ;) Just joking.
 
D

Dave Sexton

Hi Chris,

Actually, no :)

I meant, "TO all intents and purposes", and you'll notice if you look back
that I actually corrected myself in a subsequent post.

But no harm done - it is quite funny how my English not so good it is.
 
R

RobinS

Now you're starting to sound like Yoda.

Your English great not important is this. Your help appreciated
always is.

A nice day please have.

Robin S.
-------------------------
 
C

Cor Ligthert [MVP]

Warren,

Some years ago I asked in some of these dotNet newsgroups why my
combobox.text was always returning the wrong items when I had binded that to
a textbox. While I was using a datasource from the combobox. (I did not know
a website for bug reporting then).

I am still waiting for the first answer, is this the sampe problem?

Cor



Warren J. Hairston said:
Dave,

Thanks for the reply. My code isn't returning -1. Quite the contrary -
it's just that the answer isn't correct.

To make matters more interesting, I wrote a small test program wherein I
bound the DataView to a combo box and changed my query so that only 2 rows
were returned in the DataView. I bound the combo box DisplayMember to the
JobNumber field and the ValueMember to the JobID field. When I get the
SelectedValue, it's still wrong. This is similar to what I'm doing in my
program, so I think this is where the problem really lies. I can step
through with the debugger and see the contents of the combo box, but no
matter which combo box entry I select, the SelectedValue indicates that
the other value was selected.

In the code below, JobNumber and JobName should hold the same values at
the end of execution:


... //a query to populate DV (the DataView) - debugger shows everything
is OK to this point
//cbOpenJobs is a combo box in a Windows Form - bind the DV to the combo
box

DV.Sort = "JobID";

cbOpenJobs.DataSource = DV;

cbOpenJobs.DisplayMember = "JobNumber";

cbOpenJobs.ValueMember = "JobID";

... //code below executes after the user selects a value
JobID = new Guid(cbOpenJobs.SelectedValue.ToString()); //ERROR - the
value returned is not the JobID of the record I selected from the combo
box - it's the JobID of the OTHER record!?!?
JobName = cbOpenJobs.Text; //this IS correct - the JobNumber of the
record I selected from the combo box

Offset = DV.Find(JobID);

if (Offset > -1)

{

JobNumber = DV[Offset]["JobNumber"].ToString(); //this always executes,
but because JobID was incorrect, the end result is that the wrong
JobNumber is selected here

} //JobID was located

else

{

JobNumber = "";

} //JobID was not located

//by the time we get here, JobNumber and JobName (which should hold the
same value) are different



Any insight will be greatly appreciated. Thanks in advance.
- Warren

P.S.: I was aware of the "intents and purposes" phrase - that's one of my
pet peeves. Another one that I'm seeing far too often is the phrase "I
should of done that..." for "I should've [should have] done that..." LOL -
funny how we can (usually) write working programs in other languages, but
have problems with our own. If the world was a compiler, I guess we'd
never be able to communicate because of syntax errors. :)
 
W

Warren J. Hairston

Dave,

I think I found the problem - and it has nothing at all to do with setting
DataSource first (or last) or casting the Guid that is returned. My code was
returning the Guids properly, although I did implement the casting technique
that you suggested.

The problem is the line that reads:
DV.Sort = "JobID";

It appears that by sorting the DataView on a database Guid prior to binding,
the combo box rearranges the association between the values (the JobID
Guids) and the display members (the JobNumbers). I assume this is because
database Guids are sorted using only the last 6 bytes??? Or maybe the
DataView and the combo box are conflicting with each other by trying to sort
the data by different fields??? By looking at the debugger, it appears that
once bound to the combo box, the JobIDs are arranged in "database" order but
the JobNumbers (the DisplayMembers) are in alphabetical order -
unfortunately, this causes the wrong JobID to be associated with each
JobNumber.

Changing the line above to:

DV.Sort = "JobNumber";

resolved the problem.

When I have more time, I'll test the code with this line removed as well.

Now I'm just unsure whether this is a bug or by design. If the SQL query
that populates your DataView sorts the data on a different field than the
DisplayMember of the combo box it is later bound to, will the same problem
occur?

I'll research it more after I finish my project.

Thanks!
- Warren
 
W

Warren J. Hairston

Cor,

I posted what I believe to be the resolution as a response to one of Dave's
responses elsewhere under this thread. It appears my problem was related to
the fact that I had declared a sort on the DataView using one column, but
the combo box was sorting based on another column. In the process, the combo
box got confused and returned one value even though another showed in the
combo box.

- Warren
 
D

Dave Sexton

Hi Warren,

I think you might have a bug in your code somewhere since I can't reproduce
the behavior that you're observing. I've included the sample project that I
used to try the repro, after my signature.

--
Dave Sexton


{ TestForm.Designer.cs }

partial class TestForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;

/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed;
otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}

#region Windows Form Designer generated code

/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.cbOpenJobs = new System.Windows.Forms.ComboBox();
this.lblUnsorted = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.lblSort = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.lblSelected = new System.Windows.Forms.Label();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.label5 = new System.Windows.Forms.Label();
this.groupBox1.SuspendLayout();
this.SuspendLayout();
//
// cbOpenJobs
//
this.cbOpenJobs.FormattingEnabled = true;
this.cbOpenJobs.Location = new System.Drawing.Point(133, 27);
this.cbOpenJobs.Name = "cbOpenJobs";
this.cbOpenJobs.Size = new System.Drawing.Size(85, 19);
this.cbOpenJobs.TabIndex = 0;
//
// lblUnsorted
//
this.lblUnsorted.AutoSize = true;
this.lblUnsorted.Location = new System.Drawing.Point(42, 170);
this.lblUnsorted.Name = "lblUnsorted";
this.lblUnsorted.Size = new System.Drawing.Size(82, 11);
this.lblUnsorted.TabIndex = 1;
this.lblUnsorted.Text = "lblUnsorted";
//
// label2
//
this.label2.AutoSize = true;
this.label2.DataBindings.Add(new System.Windows.Forms.Binding("Text",
this.cbOpenJobs, "SelectedValue", true));
this.label2.Location = new System.Drawing.Point(94, 25);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(47, 11);
this.label2.TabIndex = 2;
this.label2.Text = "label2";
//
// lblSort
//
this.lblSort.AutoSize = true;
this.lblSort.Location = new System.Drawing.Point(45, 265);
this.lblSort.Name = "lblSort";
this.lblSort.Size = new System.Drawing.Size(54, 11);
this.lblSort.TabIndex = 1;
this.lblSort.Text = "lblSort";
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(43, 250);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(47, 11);
this.label1.TabIndex = 3;
this.label1.Text = "Sorted";
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(42, 155);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(61, 11);
this.label3.TabIndex = 3;
this.label3.Text = "Unsorted";
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(7, 25);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(89, 11);
this.label4.TabIndex = 4;
this.label4.Text = "Bound Guid: ";
//
// lblSelected
//
this.lblSelected.AutoSize = true;
this.lblSelected.Location = new System.Drawing.Point(8, 44);
this.lblSelected.Name = "lblSelected";
this.lblSelected.Size = new System.Drawing.Size(82, 11);
this.lblSelected.TabIndex = 4;
this.lblSelected.Text = "lblSelected";
//
// groupBox1
//
this.groupBox1.Controls.Add(this.label2);
this.groupBox1.Controls.Add(this.lblSelected);
this.groupBox1.Controls.Add(this.label4);
this.groupBox1.Location = new System.Drawing.Point(45, 52);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(384, 92);
this.groupBox1.TabIndex = 5;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Selection";
//
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(45, 30);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(82, 11);
this.label5.TabIndex = 6;
this.label5.Text = "Job Number:";
//
// TestForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 11F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(485, 394);
this.Controls.Add(this.label5);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.label3);
this.Controls.Add(this.label1);
this.Controls.Add(this.lblSort);
this.Controls.Add(this.lblUnsorted);
this.Controls.Add(this.cbOpenJobs);
this.Font = new System.Drawing.Font("Lucida Console", 8.25F,
System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)
(0)));
this.Name = "TestForm";
this.Text = "TestForm";
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();

}

#endregion

private System.Windows.Forms.ComboBox cbOpenJobs;
private System.Windows.Forms.Label lblUnsorted;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label lblSort;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.Label lblSelected;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.Label label5;
}


{ TestForm.cs }

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;

public partial class TestForm : Form
{
private DataTable table;

public TestForm()
{
InitializeComponent();

DataSet data = new DataSet();
table = data.Tables.Add();
table.Columns.Add("JobID", typeof(Guid));
table.Columns.Add("JobNumber", typeof(int));

table.Rows.Add(Guid.NewGuid(), 1);
table.Rows.Add(Guid.NewGuid(), 2);
table.Rows.Add(Guid.NewGuid(), 3);
table.Rows.Add(Guid.NewGuid(), 4);
table.Rows.Add(Guid.NewGuid(), 5);

table.DefaultView.Sort = "JobID";

StringBuilder tableInfo = new StringBuilder();

foreach (DataRow row in table.Rows)
{
tableInfo.AppendFormat("Job {0}; ID={1}{2}",
row["JobNumber"], row["JobID"], Environment.NewLine);
}

lblUnsorted.Text = tableInfo.ToString();

tableInfo = new StringBuilder();
int index = 0;

foreach (DataRowView rowView in table.DefaultView)
{
tableInfo.AppendFormat("Index: {1}; Job: {2}; ID={3}{0}",
Environment.NewLine, index++, rowView["JobNumber"], rowView["JobID"]);
}

lblSort.Text = tableInfo.ToString();

cbOpenJobs.SelectedIndexChanged += cbOpenJobs_SelectedIndexChanged;
cbOpenJobs.DisplayMember = "JobNumber";
cbOpenJobs.ValueMember = "JobID";
cbOpenJobs.DataSource = table.DefaultView;
}

private void cbOpenJobs_SelectedIndexChanged(object sender, EventArgs e)
{
Guid jobID = (Guid) cbOpenJobs.SelectedValue;

int foundRowIndex = table.DefaultView.Find(jobID);
int jobNumber = (int) table.DefaultView[foundRowIndex]["JobNumber"];

lblSelected.Text = string.Format(
"Found At Index: {1}{0}Job {2}{0}ID: {3}",
Environment.NewLine, foundRowIndex, jobNumber, jobID);
}
}
 
B

Bart Mermuys

Hi,

Warren J. Hairston said:
Cor,

I posted what I believe to be the resolution as a response to one of
Dave's responses elsewhere under this thread. It appears my problem was
related to the fact that I had declared a sort on the DataView using one
column, but the combo box was sorting based on another column.
In the process, the combo box got confused and returned one value even
though another showed in the combo box.

That's right, if the ComboBox is databound, it should not be sorted
(ComboBox.Sorted should be false). The DataView may be sorted. If
ComboBox.Sorted = true while databound it may return the wrong values.

If you try to sort (ComboBox.Sorted = true) after it is databound then it
will throw an ArgumentException (saying you should sort the underlying
source instead). I guess the same Exception should be thrown if you try to
set a DataSource while Sorted is already true, but it doesn't.(bug)


HTH,
Greetings
 
R

RobinS

I can't speak for the color aspect -- although if you're
spending too much time inside in front of that monitor,
you might find your skin taking on a lovely chartreuse
shade.

As for wisdom, not being wise enough myself to judge that,
I can't say, although you do appear to be fairly knowledgable.
More important than knowledge is kindness, which you have
displayed amply by helping people out.

Robin S.
-----------------------
 
W

Warren J. Hairston

Bart was right - this is a bug in the failure of the .NET ComboBox to throw
an exception. I have confirmed this from other sources on the Internet (see
links below). Hopefully Microsoft will fix this soon. Thanks for everyone's
help.
- Warren

http://www.dotnet247.com/247reference/msgs/11/57863.aspx

http://groups.google.com/group/micr...f035fc3c9e5a6/4016882a5fda82f#4016882a5fda82f

http://support.microsoft.com/kb/925730

http://groups.google.com/group/micr...c9d3eb00854/60b6903dea3e1a9f#60b6903dea3e1a9f
 

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