SQL Server Forum / DB Engine / SQL Server CE / December 2007
SqlCeConnection
|
|
Thread rating:  |
UGottaBeKidding - 12 Nov 2007 22:37 GMT I'm having some serious issues reading data from a SQL Server 2005 Mobile database. My environment is the following: VS 2005 w/ SP 1, Windows CE 5.0, and SQL Server 2005 Mobile.
I have a form with 3 buttons. The OnClick event of each button retrieves data from the database using either a DataReader, DataSet, and binding the DataSet to a DataGrid.
I have two module level SqlCeConnection objects, _con and _alwaysOpenCon. The _alwaysOpenCon stays connected until the form closes to avoid the database compacting issue. The _con object is used in each of the button click events.
I have a database with one table (Device) containing two columns (DeviceID, Name) with 10 records.
Here are my issues: 1. The DataSet and Bind takes more than 5 minutes when the dataAdapter.Fill(dataSet) is called. 2. The dataGrid1.DataSource = dataSet.Tables[0] takes more than 5 minutes. 3. After closing the application and rerunning the application, I receive an error but the Exception object does not contain a message to display. 4. My code actually has MessageBox.Show scattered throughout to show the execution. For some reason, I can't get the environment and device to communicate while debugging. The emulator doesn't help because it displays in landscape and the device screen is portrait.
Can anyone help with these issues? I figure that I must be missing something.
Thanks for you assistance.
The source code follows ---------------------------------------------------------------------------------------------- using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.SqlServerCe; using System.Drawing; using System.Text; using System.Windows.Forms;
namespace TestApp { public partial class Form1 : Form { SqlCeConnection _alwaysOpenCon = null; SqlCeConnection _con = null;
public Form1() { try { InitializeComponent(); _alwaysOpenCon = new SqlCeConnection(@"Data Source=\Program Files\TestApp\default.sdf; Password='';"); _alwaysOpenCon.Open(); } catch (Exception ex) { MessageBox.Show("Exception: " + ex.Message); } }
private void OpenConnection() { string dataSource = @"Data Source=\Program Files\TestApp\default.sdf; Password=''"; try { if (_con == null) { _con = new SqlCeConnection(dataSource); _con.Open(); }
} catch (Exception ex) { MessageBox.Show("Exception: " + ex.Message); } }
private void CloseConnection() { if (_con.State != ConnectionState.Closed) { _con.Close(); } }
private void dataReaderButton_Click(object sender, EventArgs e) { SqlCeCommand sqlCommand = null; SqlCeDataReader reader = null; try { OpenConnection();
sqlCommand = new SqlCeCommand("SELECT * FROM Device", _con); sqlCommand.CommandType = CommandType.Text; reader = sqlCommand.ExecuteReader(); while (reader.Read()) { MessageBox.Show("ID: " + reader.GetValue(0) + " - " + reader.GetValue(1)); } reader.Close(); sqlCommand.Dispose(); } catch (Exception ex) { MessageBox.Show("Exception: " + ex.Message); } finally { CloseConnection(); } }
private void dataSetButton_Click(object sender, EventArgs e) { SqlCeCommand sqlCommand; DataSet dataSet; SqlCeDataAdapter dataAdapter;
try { OpenConnection();
sqlCommand = new SqlCeCommand("SELECT * FROM Device", _con); sqlCommand.CommandType = CommandType.Text; MessageBox.Show("Set CommandText");
dataSet = new DataSet(); dataAdapter = new SqlCeDataAdapter(); dataAdapter.SelectCommand = sqlCommand; dataAdapter.Fill(dataSet);
foreach (DataRow row in dataSet.Tables[0].Rows) { MessageBox.Show("DeviceID: " + row["DeviceID"].ToString() + ": " + row["Name"].ToString()); } dataSet.Dispose(); dataAdapter.Dispose(); sqlCommand.Dispose(); } catch (Exception ex) { MessageBox.Show("Exception: " + ex.Message); } finally { CloseConnection(); } }
private void bindButton_Click(object sender, EventArgs e) { SqlCeCommand sqlCommand = null; DataSet dataSet = null; SqlCeDataAdapter dataAdapter = null;
try { OpenConnection();
sqlCommand = new SqlCeCommand("SELECT * FROM Device", _con); sqlCommand.CommandType = CommandType.Text;
dataSet = new DataSet(); dataAdapter = new SqlCeDataAdapter(); dataAdapter.SelectCommand = sqlCommand; dataAdapter.Fill(dataSet);
dataGrid1.DataSource = dataSet.Tables[0];
dataSet.Dispose(); dataAdapter.Dispose(); sqlCommand.Dispose(); } catch (Exception ex) { MessageBox.Show("Exception: " + ex.Message); } finally { CloseConnection(); } }
private void Form1_Closing(object sender, CancelEventArgs e) { this._alwaysOpenCon.Close(); } } }
Greg J - 13 Nov 2007 14:38 GMT On Nov 12, 4:37 pm, UGottaBeKidding <UGottaBeKidd...@discussions.microsoft.com> wrote:
> I'm having some serious issues reading data from a SQL Server 2005 Mobile > database. My environment is the following: VS 2005 w/ SP 1, Windows CE 5.0, [quoted text clipped - 196 lines] > > - Show quoted text - Do you have a ton of columns in that table? Try taking out the select * and only select a few columns.
We use SqlCeResultSet instead of DataReader, it is supposed to perform better, so I'm told.
SqlCeResultSet results = command.ExecuteResultSet(ResultSetOptions.Scrollable);
UGottaBeKidding - 13 Nov 2007 15:16 GMT The table does not have a ton of columns: I have a database with one table (Device) containing two columns (DeviceID, Name) with 10 records.
I did try explicitly naming the columns in the SELECT statement. Same results. Extremely slow.
I will try the SqlCeResultSet.
> On Nov 12, 4:37 pm, UGottaBeKidding > <UGottaBeKidd...@discussions.microsoft.com> wrote: [quoted text clipped - 207 lines] > SqlCeResultSet results = > command.ExecuteResultSet(ResultSetOptions.Scrollable); UGottaBeKidding - 13 Nov 2007 20:49 GMT I changed the code to use the _alwaysOpenCon object instead of the _con object. This seems to get around the issue with receiving intermittent errors when accessing the database.
I tried using the SqlCeResultSet instead of the SqlCeDataReader. The SqlCeResultSet did not perform faster than the SqlCeDataReader. I added timestamps immediately before and after calling the corresponding Execute methods of the SqlCeCommand object to compare.
Still having issues with the following: 1. The DataBind still takes an extremely long time. 2. I tried looping through SqlCeDataReader and SqlCeResultSet to populate a DataTable and then binding the DataTable. This also took a long time. 3. I tried looping through the SqlCeDataReader and create ListViewItem to populate a ListView instead of a DataGrid. This is also took a long time.
Are my expectations out of whack? I have one table with two columns and 10 records. I don't think it should take more than 5 seconds to retrieve and display the data. However, it is taking anywhere from 5 - 10 minutes.
Ginny Caughey [MVP] - 14 Nov 2007 12:53 GMT I would not expect SqlCeResultSet to be faster than SqlCeDataReader on read operations since in fact it inherits from SqlCeDataReader. The quickest way to get data on the screen for a user is to use a DataGrid databound to a SqlCeResultSet since the DataGrid only fetches the data when the user scrolls so that data would be in view (unlike ListViews where you have to completely fill it with data before the user can see anything.)
HTH,
 Signature Ginny Caughey Device Application Development MVP
>I changed the code to use the _alwaysOpenCon object instead of the _con > object. This seems to get around the issue with receiving intermittent [quoted text clipped - 17 lines] > records. I don't think it should take more than 5 seconds to retrieve and > display the data. However, it is taking anywhere from 5 - 10 minutes. UGottaBeKidding - 14 Nov 2007 14:21 GMT The SqlCeResultSet vs SqlCeDataReader was what I expected as well since as you pointed out, SqlCeResultSet inherits from SqlCeDataReader. As I understand it, the SqlCeResultSet allows data binding whereas the SqlCeDataReader does not. And, as you point out the DataGrid will display faster than the ListView.
My problem still exists: The bind operation no matter what objects I use, is EXTREMELY SLOW. It takes over 5 minutes to perform the bind. I can loop through the SqlCeDataReader and create ListViewItems for a ListView in 35 seconds. Still TOO SLOW.
Does anyone have iany deas of how to make that FASTER? That is my issue. Is something in my code setup wrong? Would it help to initialize some properties on the objects? What can be done to make retrieving and displaying the data complete in under 5 seconds? Again, I am only retrieving 10 records with two columns from one table.
Thanks
> I would not expect SqlCeResultSet to be faster than SqlCeDataReader on read > operations since in fact it inherits from SqlCeDataReader. The quickest way [quoted text clipped - 26 lines] > > records. I don't think it should take more than 5 seconds to retrieve and > > display the data. However, it is taking anywhere from 5 - 10 minutes. Ginny Caughey [MVP] - 14 Nov 2007 16:47 GMT That sounds like too much time to me too for only 10 rows. Are they the only rows in the database, or are you using a where clause to fetch them?
 Signature Ginny Caughey Device Application Development MVP
> The SqlCeResultSet vs SqlCeDataReader was what I expected as well since as > you pointed out, SqlCeResultSet inherits from SqlCeDataReader. As I [quoted text clipped - 58 lines] >> > and >> > display the data. However, it is taking anywhere from 5 - 10 minutes. UGottaBeKidding - 14 Nov 2007 16:56 GMT I agree that it sounds like too much time.
They are the only rows in that table. There are other tables in the database.
The SQL statement is: SELECT * FROM DEVICE I have also tried: SELECT DEVICEID, NAME FROM DEVICE
Both SQL statements produce the same result.
> That sounds like too much time to me too for only 10 rows. Are they the only > rows in the database, or are you using a where clause to fetch them? [quoted text clipped - 61 lines] > >> > and > >> > display the data. However, it is taking anywhere from 5 - 10 minutes. Ginny Caughey [MVP] - 14 Nov 2007 17:37 GMT I really don't know why the performance is so slow for you. I have seen a situation where there are >50000 rows in a table and I needed only 10-20 and switching to TableDirect made a huge difference, but for a table with only so few rows I just don't know. Do you have a small sample app that also creates the database that illustrates the problem?
 Signature Ginny Caughey Device Application Development MVP
>I agree that it sounds like too much time. > [quoted text clipped - 89 lines] >> >> > display the data. However, it is taking anywhere from 5 - 10 >> >> > minutes. UGottaBeKidding - 14 Nov 2007 18:23 GMT I don't have a small sample app that creates the database. I will write that and post later.
I created the database using VS 2005 and SQL Servr Management Studio. Any possibility that creating the database that way adds stuff that would slow down a query?
Either way.. I will create the small sample app and post code later.
Thanks
> I really don't know why the performance is so slow for you. I have seen a > situation where there are >50000 rows in a table and I needed only 10-20 and [quoted text clipped - 95 lines] > >> >> > display the data. However, it is taking anywhere from 5 - 10 > >> >> > minutes. Ginny Caughey [MVP] - 14 Nov 2007 18:34 GMT I look forward to your sample. I doubt that using tools to create the database causes the problem.
 Signature Ginny Caughey Device Application Development MVP
>I don't have a small sample app that creates the database. I will write >that [quoted text clipped - 121 lines] >> >> >> > display the data. However, it is taking anywhere from 5 - 10 >> >> >> > minutes. UGottaBeKidding - 14 Nov 2007 19:43 GMT Here's the code: ------------------------------------------------------------------------------------------ using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.SqlServerCe; using System.Drawing; using System.IO; using System.Text; using System.Windows.Forms;
namespace TestApp { public partial class Form1 : Form { SqlCeConnection _con = null; DateTime start; DateTime stop; string dataSource = @"Data Source=\Program Files\TestApp\default.sdf; Password='';";
public Form1() { try { InitializeComponent(); } catch (Exception ex) { MessageBox.Show("Exception: " + ex.Message); MessageBox.Show("InnerException: " + ex.InnerException.Message); } }
private void OpenConnection() {
try { if (null != _con) { _con.Close(); } _con = new SqlCeConnection(dataSource); _con.Open();
} catch (Exception ex) { MessageBox.Show("Exception: " + ex.Message); MessageBox.Show("InnerException: " + ex.InnerException.Message); } }
public void CloseConnection() { if (null != _con) { _con.Close(); } }
private void dataReaderButton_Click(object sender, EventArgs e) { SqlCeCommand sqlCommand = null; SqlCeDataReader reader = null; try { start = DateTime.Now; sqlCommand = new SqlCeCommand("SELECT DeviceID, DeviceName FROM Device", _con); sqlCommand.CommandType = CommandType.Text; reader = sqlCommand.ExecuteReader(); stop = DateTime.Now; MessageBox.Show("Time: " + new TimeSpan(stop.Ticks - start.Ticks).ToString());
while (reader.Read()) { MessageBox.Show("ID: " + reader.GetValue(0) + " - " + reader.GetValue(1)); } reader.Close(); sqlCommand.Dispose(); } catch (Exception ex) { MessageBox.Show("Exception: " + ex.Message); MessageBox.Show("InnerException: " + ex.InnerException.Message); } }
private void listDataReaderButton_Click(object sender, EventArgs e) { SqlCeCommand sqlCommand = null; SqlCeDataReader reader = null; try { start = DateTime.Now;
sqlCommand = new SqlCeCommand("SELECT DeviceID, Name FROM Device", _con); sqlCommand.CommandType = CommandType.Text; reader = sqlCommand.ExecuteReader(); stop = DateTime.Now; MessageBox.Show("Reader Time: " + new TimeSpan(stop.Ticks - start.Ticks).ToString()); string[] values; start = DateTime.Now; while (reader.Read()) { values = new string[2] { reader.GetValue(0).ToString(), reader.GetValue(1).ToString() }; listView1.Items.Add(new ListViewItem(values)); } stop = DateTime.Now;
MessageBox.Show("Populate Time: " + new TimeSpan(stop.Ticks - start.Ticks).ToString()); reader.Close(); sqlCommand.Dispose(); } catch (Exception ex) { MessageBox.Show("Exception: " + ex.Message); MessageBox.Show("InnerException: " + ex.InnerException.Message); } }
private void resultSetButton_Click(object sender, EventArgs e) { SqlCeCommand sqlCommand; SqlCeResultSet results;
try { start = DateTime.Now;
sqlCommand = new SqlCeCommand("SELECT * FROM Device", _con); sqlCommand.CommandType = CommandType.Text; //MessageBox.Show("Set CommandText");
results = sqlCommand.ExecuteResultSet(ResultSetOptions.Scrollable); //MessageBox.Show("Executed ResultSet"); //stop = DateTime.Now;
DataTable dt = new DataTable(); while (results.Read()) { //MessageBox.Show("ID: " + results.GetValue(0) + " - " + results.GetValue(1)); dt.Rows.Add(results.GetValue(0), results.GetValue(1)); } //MessageBox.Show("Time: " + new TimeSpan(stop.Ticks - start.Ticks).ToString());
dataGrid1.DataSource = dt; results.Close(); sqlCommand.Dispose(); } catch (Exception ex) { MessageBox.Show("Exception: " + ex.Message); MessageBox.Show("InnerException: " + ex.InnerException.Message); } finally { MessageBox.Show("Finally"); } }
private void bindButton_Click(object sender, EventArgs e) { SqlCeCommand sqlCommand = null; DataSet dataSet = null; SqlCeDataAdapter dataAdapter = null;
try { start = DateTime.Now;
sqlCommand = new SqlCeCommand("SELECT * FROM Device", _con); sqlCommand.CommandType = CommandType.Text;
dataSet = new DataSet(); dataAdapter = new SqlCeDataAdapter(); dataAdapter.SelectCommand = sqlCommand; dataAdapter.Fill(dataSet); stop = DateTime.Now; MessageBox.Show("Fill Time: " + new TimeSpan(stop.Ticks - start.Ticks).ToString());
start = DateTime.Now; dataGrid1.DataSource = dataSet.Tables[0]; stop = DateTime.Now; MessageBox.Show("Bind Time: " + new TimeSpan(stop.Ticks - start.Ticks).ToString());
dataSet.Dispose(); dataAdapter.Dispose(); sqlCommand.Dispose(); } catch (Exception ex) { MessageBox.Show("Exception: " + ex.Message); MessageBox.Show("InnerException: " + ex.InnerException.Message); } }
private void Form1_Closing(object sender, CancelEventArgs e) { //this._alwaysOpenCon.Close(); this._con.Close(); }
private void createButton_Click(object sender, EventArgs e) {
SqlCeCommand sqlCommand = null; int i; string sql;
try { SqlCeEngine engine = new SqlCeEngine(dataSource); engine.CreateDatabase();
OpenConnection();
sql = "CREATE TABLE [Device]([DeviceID] [int] IDENTITY(0,1) NOT NULL, [Name] [nvarchar](50) NOT NULL);"; sqlCommand = new SqlCeCommand(sql, _con); sqlCommand.CommandType = CommandType.Text; i = sqlCommand.ExecuteNonQuery();
sql = "alter table 'Device' add constraint 'PK_Device' primary key ('DeviceID');"; sqlCommand.CommandText = sql; i = sqlCommand.ExecuteNonQuery();
for (i = 0; i < 10; i++) { sqlCommand.CommandText = "INSERT INTO Device (DeviceID, DeviceName) VALUES (" + i + ", 'Device " + i + "')"; sqlCommand.ExecuteNonQuery(); }
} catch (System.Exception ex) { MessageBox.Show("Exception: " + ex.Message); } }
} }
Erik Ejlskov - 18 Nov 2007 16:09 GMT Hi,
I have made some corrections to your create table code in order to make it work.
I am not able to reproduce running a Windows CE project in the Pocket PC 2003 SE emulator (in don't have a CE 5.0 device).
Timings are (in the slow emultaor): 8 seconds to bind the resultset the first time. Less than one second following times.
There most be something bloking file access on your development system (badly behaved virus scanner or similar)
Here is my code (modified based on your code):
private void resultSetButton_Click(object sender, EventArgs e)
{
SqlCeCommand sqlCommand = null;
SqlCeResultSet results;
try
{
start = DateTime.Now;
sqlCommand = new SqlCeCommand("Device", _con);
sqlCommand.CommandType = CommandType.TableDirect;
results = sqlCommand.ExecuteResultSet(ResultSetOptions.Scrollable);
dataGrid1.DataSource = results;
stop = DateTime.Now;
MessageBox.Show("Time: " + new TimeSpan(stop.Ticks - start.Ticks).ToString());
}
catch (Exception ex)
{
MessageBox.Show("Exception: " + ex.Message);
}
finally
{
if (sqlCommand != null)
{
sqlCommand.Dispose();
}
}
}
private void createButton_Click(object sender, EventArgs e)
{
SqlCeCommand sqlCommand = null;
int i;
string sql;
try
{
SqlCeEngine engine = new SqlCeEngine(dataSource);
engine.CreateDatabase();
OpenConnection();
sql = "CREATE TABLE [Device]([DeviceID] [int] IDENTITY(0,1) NOT NULL, DeviceName [nvarchar](50) NOT NULL);";
sqlCommand = new SqlCeCommand(sql, _con);
sqlCommand.CommandType = CommandType.Text;
i = sqlCommand.ExecuteNonQuery();
sql = "alter table Device add constraint PK_Device primary key (DeviceID);";
sqlCommand.CommandText = sql;
i = sqlCommand.ExecuteNonQuery();
for (i = 0; i < 10; i++)
{
sqlCommand.CommandText = "INSERT INTO Device (DeviceName) VALUES ('Device " + i.ToString() + "')";
sqlCommand.ExecuteNonQuery();
}
}
catch (System.Exception ex)
{
MessageBox.Show("Exception: " + ex.Message);
}
}
 Signature Erik Ejlskov Jensen - see my SQL Compact blog at http://erikej.blogspot.com
> Here's the code: > ------------------------------------------------------------------------------------------ [quoted text clipped - 265 lines] > } > } chora - 18 Nov 2007 20:26 GMT I just want to do a general remark here. When performance problems rise, the first thing I would do, before diving into code, is to run the query from SQL CE Query. This would give an indication if the problem is in the code or in the database. If you get the same performance from SQL Query, thenhave a look at your columns, indexes, size of the .sdf file etc and forget about the code.
UGottaBeKidding - 19 Nov 2007 21:08 GMT I tried running SQL Query Analyzer on the device against the database I created and received an initialization error. So, I removed all SQL 2005 installations from the device. I copied the following cab files from my desktop to the device: C:\Program Files\Microsoft SQL Server 2005 Mobile Edition\Device\Client\2.0\armv4i sql.dev.ENU.wce5.armv4i.CAB sql.wce5.armv4i.CAB
C:\Program Files\Microsoft SQL Server 2005 Mobile Edition\Device\Mobile\armv4i\v3.0\armv4i\wce500 sqlce30.dev.ENU.wce5.armv4i.CAB sqlce30.wce5.armv4i.CAB
After installing the CAB file, I was able to use SQL Query Analyzer on the device. 1. I created a database (DATABASE1.sdf) on the device using SQL Query Analyzer. 2. I created a table and inserted records using SQL Query Analyzer. 3. I ran the SELECT * FROM Device in SQL Query Analyzer and it displayed the records. 4. I connected SQL Query Analyer to my original database. 5. I ran the SELECT * FROM Device in SQL Query Analyzer and it displayed the records. 6. I copied DATABASE1.sdf to use with my application. 7. I ran my application with DATABASE1.sdf and received the same error.
If I use SQL Query Analyzer to connect to either database, the records display properly. If I use either database with my application, I receive an error.
I installed the IBuySpy sample application on my desktop. When I opened the solution file, the refernce for SQLServerCEe was missing or invalid. It had the yellow triangle with an exclamation mark. So, I removed the reference and added it back pointing to C:\Program Files\Microsoft SQL Server 2005 Mobile Edition\Device\Mobile\v3.0\System.Data.sqlServerCe.dll. I compiled and deployed the IBuySpy application to the device. I modifed the IBuySpy code so that it would just open the database instead of performing the Sync or RDA. I received the same error as when I try to connect to a database using my application. I can use SQL Query Analyzer to connect to the IBuySpy database with no problem.
At this point, it seems as though my reference for System.Data.SqlServerCe are messed up. But I don't know how I can make sure that the references get cleaned up.
The references in the csproj files for my application and the IBuySpy application are exactly the same. <Reference Include="System.Data.SqlServerCe, Version=3.0.3600.0, Culture=neutral, PublicKeyToken=3be235df1c8d2ad3, processorArchitecture=MSIL" />
Does anyone have any ideas?
UGottaBeKidding - 21 Nov 2007 13:48 GMT Making some progress...
I have two versions of the sqlce30.wce5.armv4i.CAB on my development machine: The locations of the cab files are: 1. C:\Program Files\Microsoft Visual Studio 8\SmartDevices\SDK\SQL Server\Mobile\v3.0\wce500\armv4i 2. C:\Program Files\Microsoft SQL Server 2005 Mobile Edition\Device\Mobile\v3.0\wce500\armv4i
Both files are the same size. File 1 has a Date Modified of 9/3/2005 and File 2 has a Date Modified of 11/13/2005. Depending on which DLL is referenced in the project and which CAB file is installed on the device, the application will may or may not work.
What are the differences between these CAB files? Which one *should* be used?
ErikEJ - 21 Nov 2007 19:19 GMT You should download the SQL Compact SDK, and use the cab file from there: C:\Program Files\Microsoft SQL Server Compact Edition\v3.1\SDK\bin\wce500\armv4i\sqlce30.wce5.armv4i.CAB
Download from http://www.microsoft.com/downloads/details.aspx?familyid=E9AA3F8D-363D-49F3-AE89 -64E1D149E09B&displaylang=en
That is version 3.1, build 3.0.5300.0
 Signature Erik Ejlskov Jensen, Mobile App Dev MCTS Check out my SQL Compact blog at http://erikej.blogspot.com
> Making some progress... > [quoted text clipped - 14 lines] > What are the differences between these CAB files? > Which one *should* be used? Ginny Caughey [MVP] - 27 Dec 2007 15:59 GMT UGottaBeKidding,
I agree that 5 minutes to open a 10-row table with only a couple of columns seems very strange. Might there be something else going on - low memory, etc? What is the schema of your table? Is it just the first time that this takes so long and are subsequent attempts to fetch the data faster? Have you tested the time to just read through the database rather than calling Fill? I'd like to pin down exactly where the bottleneck might be.
 Signature Ginny Caughey Device Application Development MVP
> I'm having some serious issues reading data from a SQL Server 2005 Mobile > database. My environment is the following: VS 2005 w/ SP 1, Windows CE [quoted text clipped - 201 lines] > } > }
|
|
|