02
Microsoft is also releasing the Smart Device Extensions (currently in beta) which is a package containing: Microsoft .NET Compact Framework Extensions to Visual Studio .NET
http://msdn.microsoft.com/library/default.asp?url=/library/enus/dnroad/html/road10242001.asp If you need to write a database aware application, you need to use both. Once you have created a database on your PPC, you need to write ADO .NET code to access your various tables. Specifically, you are going to use the System.Data.SqlServerCe namespace in order to achieve that. You can also access a SQL Server database on a remote server using the System.Data.SqlClient namespace. This group of templates will generate that code for you. Furthermore, it will also generate DataGrids, ListViews, ListBoxes and ComboBoxes controls that are directly mapped to your specific SQL queries. Since OlyMars needs a SQL Server 2000 database to run on, here is how to set up your configuration to use efficiently this group of templates. You need to create the exact same database, both on your PC and your PPC. One easy way to do this is to create first your database on your PC (SQL Server 2000 database) then setup a replication mechanism so that the PPC version of the database will be created automatically for you. You can also create the SqlCe database by running your own SQL Code. We are going to use a database sample in this document in order to illustrate how the provided templates work.
1/29
Version : 15 dc. 02
Databases installation
SQL Server 2000 database
The name of the PC database will be DB_PC. The database schema for DB_PC is:
Create the DB_PC database on your SQL Server machine. You will find next the sql script to run in order to create those tables in the database:
2/29
Version : 15 dc. 02
Use DB_PC GO CREATE TABLE [dbo].[tblCategory] ( [Cat_GuidID] uniqueidentifier ROWGUIDCOL NOT NULL , [Cat_StrName] [varchar] (255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ) ON [PRIMARY] GO ALTER TABLE [dbo].[tblCategory] WITH NOCHECK ADD CONSTRAINT [PK_tblCategory] PRIMARY KEY CLUSTERED ([Cat_GuidID]) ON [PRIMARY], CONSTRAINT [DF_tblCategory_Cat_GuidID] DEFAULT (newid()) FOR [Cat_GuidID], CONSTRAINT [IX_tblCategory] UNIQUE NONCLUSTERED ([Cat_StrName]) ON [PRIMARY] GO CREATE TABLE [dbo].[tblProduct] ( [Pro_GuidID] uniqueidentifier ROWGUIDCOL NOT NULL , [Pro_StrName] [varchar] (255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, [Pro_CurPrice] [money] NOT NULL , [Pro_GuidCategoryID] [uniqueidentifier] NOT NULL ) ON [PRIMARY] GO ALTER TABLE [dbo].[tblProduct] WITH NOCHECK ADD CONSTRAINT [PK_tblProduct] PRIMARY KEY CLUSTERED ([Pro_GuidID]) ON [PRIMARY], CONSTRAINT [DF_tblProduct_Pro_GuidID] DEFAULT (newid()) FOR [Pro_GuidID], CONSTRAINT [IX_tblProduct] UNIQUE NONCLUSTERED ([Pro_StrName],[Pro_GuidCategoryID]) ON [PRIMARY] ALTER TABLE [dbo].[tblProduct] ADD CONSTRAINT [FK_tblProduct_tblCategory] FOREIGN KEY ([Pro_GuidCategoryID]) REFERENCES [dbo].[tblCategory] ([Cat_GuidID]) GO
3/29
Version : 15 dc. 02
public class MainClass : Form { public static void Main() { } Application.Run(new MainClass());
private Button cmdCreateDatabase = null; public MainClass() { this.cmdCreateDatabase = new System.Windows.Forms.Button(); this.cmdCreateDatabase.Location = new System.Drawing.Point(8, 8); this.cmdCreateDatabase.Size = new System.Drawing.Size(224, 40); this.cmdCreateDatabase.Text = "Create database"; this.cmdCreateDatabase.Click += new System.EventHandler(this.cmdCreateDatabase_Click); this.Controls.Add(this.cmdCreateDatabase); this.Font = new System.Drawing.Font("Verdana", 8.25F, System.Drawing.FontStyle.Regular); this.MaximizeBox = false; this.MinimizeBox = false; this.Text = "Database creator";
private void cmdCreateDatabase_Click(object sender, System.EventArgs e) { SqlCeConnection sqlCeConnection = null; try { Cursor.Current = Cursors.WaitCursor; string originalPath =.Assembly.GetExecutingAssembly().GetName().CodeBase; originalPath = Path.GetDirectoryName(originalPath); string sdfFilePath = Path.Combine(originalPath, "DB_PPC.sdf"); string sqlFilePath = Path.Combine(originalPath, "DB_PPC.sql"); string connectionString = String.Format("Data Source={0}", sdfFilePath); if (File.Exists(sdfFilePath)) { File.Delete(sdfFilePath); } SqlCeEngine sqlCeEngine = null; sqlCeEngine = new SqlCeEngine(connectionString); sqlCeEngine.CreateDatabase(); sqlCeEngine.Dispose(); TextReader textReader = File.OpenText(sqlFilePath); string[] sqlScripts = textReader.ReadToEnd().Split(';'); textReader.Close(); sqlCeConnection = new SqlCeConnection(connectionString); sqlCeConnection.Open(); SqlCeCommand sqlCeCommand = sqlCeConnection.CreateCommand(); sqlCeCommand.CommandType = CommandType.Text; foreach (string sqlScript in sqlScripts) { if (sqlScript.Trim().Length != 0) { try { sqlCeCommand.CommandText = sqlScript; sqlCeCommand.ExecuteNonQuery(); } catch (SqlCeException sqlCeException) { MessageBox.Show((String.Format("Error while executing SQL scripts:\r\n\r\n{0}", sqlCeException.Message))); return;
} } } sqlCeCommand.Dispose();
4/29
Version : 15 dc. 02
MessageBox.Show("Database successfully created!"); } catch (Exception exception) { MessageBox.Show(String.Format("Exception:\r\n\r\n{0}", exception.Message)); } finally { if (sqlCeConnection != null && sqlCeConnection.State == ConnectionState.Open) { sqlCeConnection.Close(); } Cursor.Current = Cursors.Default; } } }
Run the Build.bat command batch. On the PocketPC, create a new Folder \DB and copy both the Install.exe and DB_PPC.sql files in this folder. From the PocketPC, run the Install.exe program and click on the Create Database button. A new SDF file has been created in \DB.
5/29
Version : 15 dc. 02
Create Procedure [spI_xInsertNewCategory] ( @Cat_GuidID uniqueidentifier ,@Cat_StrName varchar(255) ) As Insert Into tblCategory (Cat_GuidID, Cat_StrName) Values (@Cat_GuidID, @Cat_StrName) Return(0) GO
Now, we can run OlyMars on this stored procedure. First, run OlyMars and connect to your DB_PC database. Then, import the DotNet Compact Framework template from the file Folder>\AddOns\ Framework.xml. <OlyMars Folder>\AddOns\DotNet Compact Framework.xml Once this new group is imported, launch the Database Extended Properties Explorer:
Create a new extended property on the spInsertNewCategory stored procedure: Name: Olymars/WindowsCE_Enabled Value = True We have just indicated to the templates that we need to be able to call this stored procedure directly on the DB_PPC database on our PPC. Lets run the generation now:
6/29
Version : 15 dc. 02
Once the generation done, lets go back to the Database Extended Properties Explorer:
As we can notice, the templates have created others needed extended properties. Since the SQL Server CE Edition does not support things like triggers, stored procedures or functions, we need to write our SQL code directly in our code.
SQL Server Centric .NET Code Generator (OlyMars) http://www.microsoft.fr/OlyMars/WebUpdate.xml
7/29
Version : 15 dc. 02
This is why an Olymars/WindowsCE_SqlQuery extended property was created. By default the whole original stored procedure SQL code was paste in there. We are now going to edit this query to be SQL Server CE Edition compliant. Update the Olymars/WindowsCE_SqlQuery extended property this way: Name: Olymars/WindowsCE_SqlQuery Value: Insert Into tblCategory (Cat_GuidID, Cat_StrName) Values (?, ?) Notice that we have replaced our parameter by a question mark (?). We are now ready to generate all the code again since we have updated the SqlQuery property. If we browse the output directory we can notice that a CE directory was created and that we have a build file ready to use.
Before running this batch, be aware that it uses some specific environment variables to locate C# compiler and the .NET Compact Framework runtime: Name = OLYMARS_FXBIN1.1 OLYMARS_FXBIN1.1 OLYMARS_FXBIN1.1 Value = C:\WINNT\Microsoft.NET\Framework\v1.1.4322 C:\ C: WINNT\Microsoft.NET\Framework\v1.1.4322 Name = OLYMARS_FXSDK1.1 OLYMARS_FXSDK1.1 OLYMARS_FXSDK1.1 Value = C:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\Bin C:\ Files\Microsoft 2003\SDK\v1.1\Bin C: Name = OLYMARS_CFXBIN1.0 OLYMARS_CFXBIN1.0 OLYMARS_CFXBIN1.0 Value = C:\Program Files\Microsoft Visual Studio .NET Files\ : 2003\CompactFrameworkSDK\v1.0.5000\ 2003\CompactFrameworkSDK\v1.0.5000\Windows CE CE For you convenience, you will find a reg file on the root of the OlyMars binaries that creates all the necessary environment variables (with default values) for you:
8/29
Version : 15 dc. 02
Once your environment variables are correctly set up, run the batch file and ignore the errors for now:
You have now access to an assembly built specifically for the .NET Compact Framework: \DB_PC\CE\Bin\DB_PC.Ce.dll DB_PC\CE\Bin\ In order to call our Stored Procedure directly from the PPC, we now have two useful classes: DB_PC.Ce.DataClasses.Parameters.spInsertNewCategory DB_PC.Ce.DataClasses.StoredProcedures.spInsertNewCategory If you are used to the classical OlyMars templates (DotNet Framework Data classes), you now know how to call those classes right? If not, here is an example: Create a new C# SDE Windows Application project named PPC_Client PPC_Client.
9/29
Version : 15 dc. 02
Update the Output File Folder property of the project to \DB. \DB Add the following references:
10/29
Version : 15 dc. 02
Add a new TexBox (textBox1 and a new Button (button1 on Form1. textBox1) button1) textBox1 button1
11/29
Version : 15 dc. 02
12/29
Version : 15 dc. 02
private void button1_Click(object sender, System.EventArgs e) { string currentPath = Assembly.GetExecutingAssembly().GetName().CodeBase; currentPath = Path.GetDirectoryName(currentPath); string connectionstring = Information.BuildConnectionString (Path.Combine(currentPath, "DB_PPC.sdf")); Params.spI_xInsertNewCategory param = null; Param = new Params.spI_xInsertNewCategory(); param.SetUpConnection(connectionstring); param.Param_Cat_GuidID = new SqlGuid("{BD51E6FC-9293-4FC0-9BE9-13D1E0519922}"); param.Param_Cat_StrName = textBox1.Text; SPs.spI_xInsertNewCategory sp = null; using (sp = new SPs.spI_xInsertNewCategory(true)) { try { sp.Execute(ref param); MessageBox.Show("Category successfully created"); } catch(System.Data.SqlServerCe.SqlCeException sqlCeException) { MessageBox.Show(sqlCeException.Message); } catch (System.Exception Exception) { MessageBox.Show(Exception.Message); } } param.Dispose(); }
13/29
Version : 15 dc. 02
If you click again on the button you will have the following error:
This is because the Cat_StrName was declared as a unique key. Lets verify if the new record is actually in the database:
14/29
Version : 15 dc. 02
OK, thats cool our record is there. Lets go back now to our DB_PC database and lets add a new stored procedure spU_xUpdateCategory: U_xUpdateCategory spU_xUpdateCategory
Create Procedure spU_xUpdateCategory ( @Cat_GuidID uniqueidentifier ,@Cat_StrName varchar(255) ) As Update tblcategory Set Cat_StrName = @Cat_StrName Where Cat_GuidID = @Cat_GuidID Return(0)
From OlyMars, refresh the database. As for the previous stored procedure, add a new extended property Olymars/WindowsCE_Enabled and set it to True Lets now Olymars/WindowsCE_Enabled True. Olymars/WindowsCE_Enabled run again a generation on the whole thing:
15/29
Version : 15 dc. 02
You now should see those extended properties for our stored procedure:
16/29
Version : 15 dc. 02
As you can notice, we are going to have some problems with the parameters because @Cat_GuidID is supposed to be the FIRST parameter and @Cat_StrName the second one. But when we have replaced the parameters by our question mark (?), the order is exactly reversed. The first ? is intended for @Cat_StrName and the second one is intended for @Cat_GuidID. This is where the Olymars/WindowsCE_ParametersMapping extended property comes Olymars/WindowsCE_ParametersMapping Olymars/WindowsCE_ParametersMapping into the picture. We are going to reflect that situation by updating those extended properties this way:
Now we have indicated that @Cat_GuidID actually maps to the second ?(Mapping=1) and that @Cat_StrName maps to the first one (Mapping=0). Lets go ahead and regenerate the whole stuff (Close your Visual Studio .NET solution before that). Once the assembly recompiled using the batch file, lets go back to Visual Studio .NET project and lets rebuild the project to update the assembly reference. Lets add two TextBoxes (textBox2) and a button (button2):
17/29
Version : 15 dc. 02
private void button3_Click(object sender, System.EventArgs e) { string currentPath = Assembly.GetExecutingAssembly().GetName().CodeBase; currentPath = Path.GetDirectoryName(currentPath); string connectionstring = Information.BuildConnectionString (Path.Combine(currentPath, "DB_PPC.sdf")); Params.spU_xUpdateCategory param = null; param=new Params.spU_xUpdateCategory(); param.SetUpConnection(connectionstring); param.Param_Cat_GuidID = new SqlGuid("{BD51E6FC-9293-4FC0-9BE9-13D1E0519922}"); param.Param_Cat_StrName = textBox2.Text; SPs.spU_xUpdateCategory sp = null; using (sp = new SPs.spU_xUpdateCategory(true)) { try { sp.Execute(ref param); MessageBox.Show("Category successfully updated"); } catch(System.Data.SqlServerCe.SqlCeException sqlCeException) { MessageBox.Show(sqlCeException.Message); } catch (System.Exception Exception) { MessageBox.Show(Exception.Message); } } param.Dispose(); }
18/29
Version : 15 dc. 02
From OlyMars, refresh the database. As for the previous stored procedure, add a Olymars/WindowsCE_Enabled True. new extended property Olymars/WindowsCE_Enabled and set it to True Lets now Olymars/WindowsCE_Enabled run again a generation on the whole thing. Lets update the SqlQuery extended property like this:
19/29
Version : 15 dc. 02
Lets run again the generation and recompile the assembly again.
20/29
Version : 15 dc. 02
Since there is at least one stored procedure that returns some data, you now have access to visual controls. In order to successfully use them, you need to customize Visual Studio .NET toolbox.
Click on the Browse button and pick up the following assembly: C:\Program Files\Microsoft Visual Studio .NET C:\ Files\ C: 2003\CompactFrameworkSDK\v1.0.5000\ CE\Designer\Design.DB_PC.Ce.dll DB_PC.Ce.dll 2003\CompactFrameworkSDK\v1.0.5000\Windows CE\Designer\Design.DB_PC.Ce.dll
21/29
Version : 15 dc. 02
Then
22/29
Version : 15 dc. 02
23/29
Version : 15 dc. 02
24/29
Version : 15 dc. 02
From OlyMars, refresh the database. As for the previous stored procedure, add a new extended property Olymars/WindowsCE_Enabled and set it to True Lets now True. run again a generation on the whole thing. Lets update the SqlQuery extended property like this:
25/29
Version : 15 dc. 02
Lets run again the generation and recompile the assembly again. In Visual Studio .NET, add a new Form (form2), add a ListView (listView1, View=Details) and a Button (button1):
Double-Click the button1. From now on and because of a bug in SDE, we are going to close the Form2 design windows. In the source code, we are going to replace the two instances of System.Windows.Forms.ListView by DB_PC.Ce.Windows.ListViews.WinListViewCustom_spGetSomeCategories:
26/29
Version : 15 dc. 02
And
Update the project to start on form2 instead of Form1. Finally add the button1 click event handler: private void button1_Click(object sender, System.EventArgs e) { string connectionstring; connectionstring=DB_PC.Ce.DataClasses.Information.BuildConnectionString(@"\M y Documents\DB_PPC.sdf"); DB_PC.Ce.Windows.ListViewParameters ListViewParameters; DB_PC.Ce.Windows.ListViewParameter ListViewParameter; ListViewParameter = new DB_PC.Ce.Windows.ListViewParameter("Cat_StrName","Name"); ListViewParameters = new DB_PC.Ce.Windows.ListViewParameters("Cat_GuidID",ListViewParameter); ListViewParameter = new DB_PC.Ce.Windows.ListViewParameter("Cat_GuidID","Guid"); ListViewParameters.AddSubItem(ListViewParameter); try { listView1.Initialize(connectionstring,ListViewParameters,"A","T"); listView1.RefreshData(); } catch (DB_PC.Ce.DataClasses.CustomException ee) {
SQL Server Centric .NET Code Generator (OlyMars) http://www.microsoft.fr/OlyMars/WebUpdate.xml
27/29
Version : 15 dc. 02
MessageBox.Show(ee.Parameter.SqlCeException.Message); } }
28/29
Version : 15 dc. 02
Compile and deploy: Erreur de compile : The modifier 'private' is not valid for this item pour la ligne private void listView1.SelectedIndexChanged (object sender, System.EventArgs e) ????
29/29