diff --git a/Local.testsettings b/Local.testsettings
new file mode 100644
index 0000000..b25fff1
--- /dev/null
+++ b/Local.testsettings
@@ -0,0 +1,10 @@
+
+
+ These are default test settings for a local test run.
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OpenNETCF.ORM.FFx.sln b/OpenNETCF.ORM.FFx.sln
index c5e52be..2d329a8 100644
--- a/OpenNETCF.ORM.FFx.sln
+++ b/OpenNETCF.ORM.FFx.sln
@@ -7,9 +7,22 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenNETCF.ORM.SqlCe.FFx", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EntityGenerator", "EntityGenerator\EntityGenerator.csproj", "{5BAFE144-30A1-4D9A-A267-1BEE62E45D2C}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C64CCC7B-9F5F-4D99-8154-BDF0727FE98F}"
+ ProjectSection(SolutionItems) = preProject
+ Local.testsettings = Local.testsettings
+ OpenNETCF.ORM.FFx.vsmdi = OpenNETCF.ORM.FFx.vsmdi
+ TraceAndTestImpact.testsettings = TraceAndTestImpact.testsettings
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenNETCF.ORM.SqlCE.Integration.Test", "OpenNETCF.ORM.SqlCE.Integration.Test\OpenNETCF.ORM.SqlCE.Integration.Test.csproj", "{5A05D8DE-100E-4443-9FBA-BEA87A070732}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenNETCF.ORM.SQLite.FFx", "OpenNETCF.ORM.SQLite\OpenNETCF.ORM.SQLite.FFx.csproj", "{750ED0AF-FE89-4EFC-BF7A-C29CBDD8AA7F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenNETCF.ORM.SQLite.Integration.Test", "OpenNETCF.ORM.SQLite.Integration.Test\OpenNETCF.ORM.SQLite.Integration.Test.csproj", "{97A3ADC5-EED5-4BC8-BE5B-1FD8DF86A1C3}"
+EndProject
Global
GlobalSection(TeamFoundationVersionControl) = preSolution
- SccNumberOfProjects = 4
+ SccNumberOfProjects = 7
SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
SccTeamFoundationServer = https://tfs.codeplex.com/tfs/tfs01
SccLocalPath0 = .
@@ -22,6 +35,18 @@ Global
SccProjectUniqueName3 = EntityGenerator\\EntityGenerator.csproj
SccProjectName3 = EntityGenerator
SccLocalPath3 = EntityGenerator
+ SccProjectUniqueName4 = OpenNETCF.ORM.SqlCE.Integration.Test\\OpenNETCF.ORM.SqlCE.Integration.Test.csproj
+ SccProjectName4 = OpenNETCF.ORM.SqlCE.Integration.Test
+ SccLocalPath4 = OpenNETCF.ORM.SqlCE.Integration.Test
+ SccProjectUniqueName5 = OpenNETCF.ORM.SQLite\\OpenNETCF.ORM.SQLite.FFx.csproj
+ SccProjectName5 = OpenNETCF.ORM.SQLite
+ SccLocalPath5 = OpenNETCF.ORM.SQLite
+ SccProjectUniqueName6 = OpenNETCF.ORM.SQLite.Integration.Test\\OpenNETCF.ORM.SQLite.Integration.Test.csproj
+ SccProjectName6 = OpenNETCF.ORM.SQLite.Integration.Test
+ SccLocalPath6 = OpenNETCF.ORM.SQLite.Integration.Test
+ EndGlobalSection
+ GlobalSection(TestCaseManagementSettings) = postSolution
+ CategoryFile = OpenNETCF.ORM.FFx.vsmdi
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -40,6 +65,18 @@ Global
{5BAFE144-30A1-4D9A-A267-1BEE62E45D2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5BAFE144-30A1-4D9A-A267-1BEE62E45D2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5BAFE144-30A1-4D9A-A267-1BEE62E45D2C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5A05D8DE-100E-4443-9FBA-BEA87A070732}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5A05D8DE-100E-4443-9FBA-BEA87A070732}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5A05D8DE-100E-4443-9FBA-BEA87A070732}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5A05D8DE-100E-4443-9FBA-BEA87A070732}.Release|Any CPU.Build.0 = Release|Any CPU
+ {750ED0AF-FE89-4EFC-BF7A-C29CBDD8AA7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {750ED0AF-FE89-4EFC-BF7A-C29CBDD8AA7F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {750ED0AF-FE89-4EFC-BF7A-C29CBDD8AA7F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {750ED0AF-FE89-4EFC-BF7A-C29CBDD8AA7F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {97A3ADC5-EED5-4BC8-BE5B-1FD8DF86A1C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {97A3ADC5-EED5-4BC8-BE5B-1FD8DF86A1C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {97A3ADC5-EED5-4BC8-BE5B-1FD8DF86A1C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {97A3ADC5-EED5-4BC8-BE5B-1FD8DF86A1C3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/OpenNETCF.ORM.FFx.vsmdi b/OpenNETCF.ORM.FFx.vsmdi
new file mode 100644
index 0000000..2441ca8
--- /dev/null
+++ b/OpenNETCF.ORM.FFx.vsmdi
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OpenNETCF.ORM.SQLite.Integration.Test/OpenNETCF.ORM.SQLite.Integration.Test.csproj b/OpenNETCF.ORM.SQLite.Integration.Test/OpenNETCF.ORM.SQLite.Integration.Test.csproj
new file mode 100644
index 0000000..2799e90
--- /dev/null
+++ b/OpenNETCF.ORM.SQLite.Integration.Test/OpenNETCF.ORM.SQLite.Integration.Test.csproj
@@ -0,0 +1,81 @@
+
+
+
+ Debug
+ AnyCPU
+
+
+ 2.0
+ {97A3ADC5-EED5-4BC8-BE5B-1FD8DF86A1C3}
+ Library
+ Properties
+ OpenNETCF.ORM.SQLite.Integration.Test
+ OpenNETCF.ORM.SQLite.Integration.Test
+ v4.0
+ 512
+ {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ SAK
+ SAK
+ SAK
+ SAK
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+ 3.5
+
+
+
+
+ False
+ ..\OpenNETCF.ORM.SQLite\references\FFx\x64\System.Data.SQLite.dll
+
+
+
+
+
+
+ False
+
+
+
+
+
+
+
+
+ {750ED0AF-FE89-4EFC-BF7A-C29CBDD8AA7F}
+ OpenNETCF.ORM.SQLite.FFx
+
+
+ {6E9C7DA3-AD60-4E44-9D3A-7BBD3A20D79F}
+ OpenNETCF.ORM.FFx
+
+
+
+
+
\ No newline at end of file
diff --git a/OpenNETCF.ORM.SQLite.Integration.Test/OpenNETCF.ORM.SQLite.Integration.Test.csproj.vspscc b/OpenNETCF.ORM.SQLite.Integration.Test/OpenNETCF.ORM.SQLite.Integration.Test.csproj.vspscc
new file mode 100644
index 0000000..feffdec
--- /dev/null
+++ b/OpenNETCF.ORM.SQLite.Integration.Test/OpenNETCF.ORM.SQLite.Integration.Test.csproj.vspscc
@@ -0,0 +1,10 @@
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = ""
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
+}
diff --git a/OpenNETCF.ORM.SQLite.Integration.Test/Properties/AssemblyInfo.cs b/OpenNETCF.ORM.SQLite.Integration.Test/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..7eb9199
--- /dev/null
+++ b/OpenNETCF.ORM.SQLite.Integration.Test/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("OpenNETCF.ORM.SQLite.Integration.Test")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("OpenNETCF.ORM.SQLite.Integration.Test")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("f7a90bd8-a393-4720-bb1d-705ca58e2f00")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenNETCF.ORM.SQLite.Integration.Test/SQLiteDataStoreTest.cs b/OpenNETCF.ORM.SQLite.Integration.Test/SQLiteDataStoreTest.cs
new file mode 100644
index 0000000..b729e2a
--- /dev/null
+++ b/OpenNETCF.ORM.SQLite.Integration.Test/SQLiteDataStoreTest.cs
@@ -0,0 +1,46 @@
+using OpenNETCF.ORM.SQLite;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+
+namespace OpenNETCF.ORM.SQLite.Integration.Test
+{
+ [TestClass()]
+ public class SQLiteDataStoreTest
+ {
+ public TestContext TestContext { get; set; }
+ [TestMethod()]
+ [DeploymentItem("OpenNETCF.ORM.SqlCe.dll")]
+ public void SelectTest()
+ {
+ var store = new SQLiteDataStore("test.db");
+ store.AddType();
+ store.CreateStore();
+
+ store.Insert(new TestItem("ItemA"));
+ //store.Insert(new TestItem("ItemB"));
+ //store.Insert(new TestItem("ItemC"));
+
+ //var item = store.Select("Name", "ItemB").FirstOrDefault();
+ //item = store.Select(2);
+ }
+ }
+
+ [Entity(KeyScheme=KeyScheme.Identity)]
+ public class TestItem
+ {
+ public TestItem()
+ {
+ }
+
+ public TestItem(string name)
+ {
+ Name = name;
+ }
+
+ [Field(IsPrimaryKey=true)]
+ int ID { get; set; }
+
+ [Field]
+ string Name { get; set; }
+ }
+}
diff --git a/OpenNETCF.ORM.SQLite/OpenNETCF.ORM.SQLite.FFx.csproj b/OpenNETCF.ORM.SQLite/OpenNETCF.ORM.SQLite.FFx.csproj
new file mode 100644
index 0000000..6ceefc6
--- /dev/null
+++ b/OpenNETCF.ORM.SQLite/OpenNETCF.ORM.SQLite.FFx.csproj
@@ -0,0 +1,74 @@
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {750ED0AF-FE89-4EFC-BF7A-C29CBDD8AA7F}
+ Library
+ Properties
+ OpenNETCF.ORM.SQLite.FFx
+ OpenNETCF.ORM.SQLite.FFx
+ v3.5
+ 512
+ SAK
+ SAK
+ SAK
+ SAK
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+ False
+ references\FFx\x32\System.Data.SQLite.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {6E9C7DA3-AD60-4E44-9D3A-7BBD3A20D79F}
+ OpenNETCF.ORM.FFx
+
+
+
+
+ PreserveNewest
+
+
+
+
+
\ No newline at end of file
diff --git a/OpenNETCF.ORM.SQLite/OpenNETCF.ORM.SQLite.FFx.csproj.vspscc b/OpenNETCF.ORM.SQLite/OpenNETCF.ORM.SQLite.FFx.csproj.vspscc
new file mode 100644
index 0000000..feffdec
--- /dev/null
+++ b/OpenNETCF.ORM.SQLite/OpenNETCF.ORM.SQLite.FFx.csproj.vspscc
@@ -0,0 +1,10 @@
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = ""
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
+}
diff --git a/OpenNETCF.ORM.SQLite/SQLite.Interop.dll b/OpenNETCF.ORM.SQLite/SQLite.Interop.dll
new file mode 100644
index 0000000..6446d92
Binary files /dev/null and b/OpenNETCF.ORM.SQLite/SQLite.Interop.dll differ
diff --git a/OpenNETCF.ORM.SQLite/SQLiteDataStore.cs b/OpenNETCF.ORM.SQLite/SQLiteDataStore.cs
index 96067d7..e7afd6c 100644
--- a/OpenNETCF.ORM.SQLite/SQLiteDataStore.cs
+++ b/OpenNETCF.ORM.SQLite/SQLiteDataStore.cs
@@ -1,313 +1,307 @@
using System;
using System.Net;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Documents;
-using System.Windows.Ink;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Animation;
-using System.Windows.Shapes;
-using Community.CsharpSqlite;
using System.IO;
using System.Diagnostics;
using System.Text;
using System.Linq;
using System.Data;
+using System.Data.SQLite;
+using System.Data.Common;
namespace OpenNETCF.ORM.SQLite
{
- public class SQLiteDataStore : DataStore, IDisposable
+ public class SQLiteDataStore : SQLStoreBase, IDisposable
{
- private Sqlite3.sqlite3 m_store;
- private string m_storeName;
+ private string m_connectionString;
- public int DefaultStringFieldSize { get; set; }
- public int DefaultNumericFieldPrecision { get; set; }
+ public string FileName { get; protected set; }
- public SQLiteDataStore(string databaseName)
+ protected SQLiteDataStore()
+ : base()
{
- if (string.IsNullOrEmpty(databaseName))
- {
- throw new ArgumentException();
- }
-
- m_storeName = databaseName;
- DefaultStringFieldSize = 200;
- DefaultNumericFieldPrecision = 16;
-
- OpenStore();
- }
-
- public override void CreateStore()
- {
- foreach (var entity in this.Entities)
- {
- CreateTable(entity);
- }
+// UseCommandCache = true;
}
- public override void DeleteStore()
+ public SQLiteDataStore(string fileName)
+ : this()
{
- if (m_store != null)
- {
- CloseStore();
- }
-
- if (StoreExists)
+ if (string.IsNullOrEmpty(fileName))
{
- File.Delete(m_storeName);
+ throw new ArgumentException();
}
- }
-
- public override bool StoreExists
- {
- get { return File.Exists(m_storeName); }
- }
-
- public override void Insert(object item, bool insertReferences)
- {
- throw new NotImplementedException();
- }
-
- public override T[] Select()
- {
- throw new NotImplementedException();
- }
-
- public override T Select(object primaryKey)
- {
- throw new NotImplementedException();
- }
-
- public override T[] Select(string searchFieldName, object matchValue)
- {
- throw new NotImplementedException();
- }
-
- public override void Update(object item)
- {
- throw new NotImplementedException();
- }
-
- public override void Delete(object item)
- {
- throw new NotImplementedException();
- }
- public override void Delete(object primaryKey)
- {
- throw new NotImplementedException();
+ FileName = fileName;
}
- public override void FillReferences(object instance)
+ private string ConnectionString
{
- throw new NotImplementedException();
- }
-
- public override T[] Fetch(int fetchCount)
- {
- throw new NotImplementedException();
- }
+ get
+ {
+ if (m_connectionString == null)
+ {
+ m_connectionString = string.Format("Data Source={0}", FileName);
- public override T[] Fetch(int fetchCount, int firstRowOffset)
- {
- throw new NotImplementedException();
+ }
+ return m_connectionString;
+ }
}
- public override int Count()
+ protected override System.Data.Common.DbCommand GetNewCommandObject()
{
- throw new NotImplementedException();
+ return new SQLiteCommand();
}
- public override void Delete()
+ protected override System.Data.Common.DbConnection GetNewConnectionObject()
{
- throw new NotImplementedException();
+ return new SQLiteConnection(ConnectionString);
}
- public override void Delete(string fieldName, object matchValue)
+ protected override string AutoIncrementFieldIdentifier
{
- throw new NotImplementedException();
+ get { return "AUTOINCREMENT"; }
}
- public override bool Contains(object item)
- {
- throw new NotImplementedException();
- }
-
- public void Dispose()
+ public override void CreateStore()
{
- if (m_store != null)
+ if (StoreExists)
{
- CloseStore();
+ throw new StoreAlreadyExistsException();
}
- }
- private void OpenStore()
- {
- m_store = new Sqlite3.sqlite3();
+ SQLiteConnection.CreateFile(FileName);
- var result = Sqlite3.sqlite3_open(m_storeName, ref m_store);
-
- if (result != Sqlite3.SQLITE_OK)
+ var connection = GetConnection(true);
+ try
+ {
+ foreach (var entity in this.Entities)
+ {
+ CreateTable(connection, entity);
+ }
+ }
+ finally
{
- throw new SQLiteException(Sqlite3.sqlite3_errmsg(m_store));
+ DoneWithConnection(connection, true);
}
}
- private void CloseStore()
+ public override void DeleteStore()
{
- var result = Sqlite3.sqlite3_close(m_store);
- if (result != Sqlite3.SQLITE_OK)
+ if (StoreExists)
{
- throw new SQLiteException(Sqlite3.sqlite3_errmsg(m_store));
+ File.Delete(FileName);
}
- m_store = null;
}
- private void CreateTable(EntityInfo entity)
+ public override bool StoreExists
{
- StringBuilder sql = new StringBuilder();
-
- if (ReservedWords.Contains(entity.EntityName, StringComparer.InvariantCultureIgnoreCase))
- {
- throw new ReservedWordException(entity.EntityName);
- }
+ get { return File.Exists(FileName); }
+ }
- sql.AppendFormat("CREATE TABLE {0} (", entity.EntityName);
+ private SQLiteCommand GetInsertCommand(string entityName)
+ {
+ // TODO: support command caching to improve bulk insert speeds
+ // simply use a dictionary keyed by entityname
+ var keyScheme = Entities[entityName].EntityAttribute.KeyScheme;
+ var insertCommand = new SQLiteCommand();
- int count = entity.Fields.Count;
+ var sbFields = new StringBuilder(string.Format("INSERT INTO {0} (", entityName));
+ var sbParams = new StringBuilder( " VALUES (");
- foreach (var field in entity.Fields)
+ foreach (var field in Entities[entityName].Fields)
{
- if (ReservedWords.Contains(field.FieldName, StringComparer.InvariantCultureIgnoreCase))
+ // skip auto-increments
+ if ((field.IsPrimaryKey) && (keyScheme == KeyScheme.Identity))
{
- throw new ReservedWordException(field.FieldName);
+ continue;
}
+ sbFields.Append("[" + field.FieldName + "],");
+ sbParams.Append("?,");
- sql.AppendFormat("[{0}] {1} {2}",
- field.FieldName,
- GetFieldDataTypeString(entity.EntityName, field),
- GetFieldCreationAttributes(entity.EntityAttribute, field));
-
- if (--count > 0) sql.Append(", ");
+ insertCommand.Parameters.Add(new SQLiteParameter(field.FieldName));
}
- sql.Append(")");
+ // replace trailing commas
+ sbFields[sbFields.Length - 1] = ')';
+ sbParams[sbParams.Length - 1] = ')';
- Debug.WriteLine(sql);
- string error = string.Empty;
- var result = Sqlite3.sqlite3_exec(m_store, sql.ToString(), CommandCallback, null, ref error);
- if (result != Sqlite3.SQLITE_OK)
- {
- throw new SQLiteException(Sqlite3.sqlite3_errmsg(m_store));
- }
- }
+ insertCommand.CommandText = sbFields.ToString() + sbParams.ToString();
- private int CommandCallback(object pArg, long nArg, object azArgs, object azCols)
- {
- return 0;
+ return insertCommand;
}
- private string GetFieldDataTypeString(string entityName, FieldAttribute field)
+ ///
+ /// Inserts the provided entity instance into the underlying data store.
+ ///
+ ///
+ ///
+ /// If the entity has an identity field, calling Insert will populate that field with the identity vale vefore returning
+ ///
+ public override void Insert(object item, bool insertReferences)
{
- // the SQL RowVersion is a special case
- if (field.IsRowVersion)
- {
- switch (field.DataType)
- {
- case DbType.UInt64:
- case DbType.Int64:
- // no error
- break;
- default:
- throw new FieldDefinitionException(entityName, field.FieldName, "rowversion fields must be an 8-byte data type (In64 or UInt64)");
- }
+ var itemType = item.GetType();
+ string entityName = m_entities.GetNameForType(itemType);
- return "rowversion";
+ if (entityName == null)
+ {
+ throw new EntityNotFoundException(item.GetType());
}
- return field.DataType.ToSqlTypeString();
- }
+ var connection = GetConnection(false);
+ try
+ {
+ // CheckOrdinals(entityName);
- private string GetFieldCreationAttributes(EntityAttribute attribute, FieldAttribute field)
- {
- StringBuilder sb = new StringBuilder();
+ FieldAttribute identity = null;
+ var command = GetInsertCommand(entityName);
+ command.Connection = connection as SQLiteConnection;
- switch (field.DataType)
- {
- case DbType.String:
- if (field.Length > 0)
+ var keyScheme = Entities[entityName].EntityAttribute.KeyScheme;
+
+ // TODO: fill the parameters
+ foreach (var field in Entities[entityName].Fields)
+ {
+ if ((field.IsPrimaryKey) && (keyScheme == KeyScheme.Identity))
+ {
+ identity = field;
+ continue;
+ }
+ else if (field.DataType == DbType.Object)
{
- sb.AppendFormat("({0}) ", field.Length);
+ // get serializer
+ var serializer = GetSerializer(itemType);
+
+ if (serializer == null)
+ {
+ throw new MissingMethodException(
+ string.Format("The field '{0}' requires a custom serializer/deserializer method pair in the '{1}' Entity",
+ field.FieldName, entityName));
+ }
+ var value = serializer.Invoke(item, new object[] { field.FieldName });
+ if (value == null)
+ {
+ command.Parameters[field.FieldName].Value = DBNull.Value;
+ }
+ else
+ {
+ command.Parameters[field.FieldName].Value = value;
+ }
+ }
+ else if (field.IsRowVersion)
+ {
+ // read-only, so do nothing
+ }
+ else if (field.PropertyInfo.PropertyType.UnderlyingTypeIs())
+ {
+ // SQL Compact doesn't support Time, so we're convert to a DateTime both directions
+ var value = field.PropertyInfo.GetValue(item, null);
+
+ if (value == null)
+ {
+ command.Parameters[field.FieldName].Value = DBNull.Value;
+ }
+ else
+ {
+ var timespanTicks = ((TimeSpan)value).Ticks;
+ command.Parameters[field.FieldName].Value = timespanTicks;
+ }
}
else
{
- sb.AppendFormat("({0}) ", DefaultStringFieldSize);
+ var value = field.PropertyInfo.GetValue(item, null);
+ command.Parameters[field.FieldName].Value = value;
}
- break;
- case DbType.Decimal:
- int p = field.Precision == 0 ? DefaultNumericFieldPrecision : field.Precision;
- sb.AppendFormat("({0},{1}) ", p, field.Scale);
- break;
- }
+ }
- if (field.IsPrimaryKey)
- {
- sb.Append("PRIMARY KEY ");
+ command.ExecuteNonQuery();
- if (attribute.KeyScheme == KeyScheme.Identity)
+ // did we have an identity field? If so, we need to update that value in the item
+ if (identity != null)
{
- switch (field.DataType)
+ var id = GetIdentity(connection);
+ identity.PropertyInfo.SetValue(item, id, null);
+ }
+
+ if (insertReferences)
+ {
+ // cascade insert any References
+ // do this last because we need the PK from above
+ foreach (var reference in Entities[entityName].References)
{
- case DbType.Int32:
- case DbType.UInt32:
- sb.Append("IDENTITY ");
- break;
- case DbType.Guid:
- sb.Append("ROWGUIDCOL ");
- break;
- default:
- throw new FieldDefinitionException(attribute.NameInStore, field.FieldName,
- string.Format("Data Type '{0}' cannot be marked as an Identity field", field.DataType));
+ var valueArray = reference.PropertyInfo.GetValue(item, null);
+ if (valueArray == null) continue;
+
+ var fk = Entities[entityName].Fields[reference.ReferenceField].PropertyInfo.GetValue(item, null);
+
+ string et = null;
+
+ // we've already enforced this to be an array when creating the store
+ foreach (var element in valueArray as Array)
+ {
+ if (et == null)
+ {
+ et = m_entities.GetNameForType(element.GetType());
+ }
+
+ // get the FK value
+ var keyValue = Entities[et].Fields.KeyField.PropertyInfo.GetValue(element, null);
+
+ bool isNew = false;
+
+
+ // only do an insert if the value is new (i.e. need to look for existing reference items)
+ // not certain how this will work right now, so for now we ask the caller to know what they're doing
+ switch (keyScheme)
+ {
+ case KeyScheme.Identity:
+ // TODO: see if PK field value == -1
+ isNew = keyValue.Equals(-1);
+ break;
+ case KeyScheme.GUID:
+ // TODO: see if PK field value == null
+ isNew = keyValue.Equals(null);
+ break;
+ }
+
+ if (isNew)
+ {
+ Entities[et].Fields[reference.ReferenceField].PropertyInfo.SetValue(element, fk, null);
+ Insert(element);
+ }
+ }
}
}
}
-
- if (!field.AllowsNulls)
+ finally
{
- sb.Append("NOT NULL ");
+ DoneWithConnection(connection, false);
}
+ }
- if (field.RequireUniqueValue)
+ private int GetIdentity(DbConnection connection)
+ {
+ using (var command = new SQLiteCommand("SELECT last_insert_rowid()", connection as SQLiteConnection))
{
- sb.Append("UNIQUE ");
+ object id = command.ExecuteScalar();
+ return Convert.ToInt32(id);
}
-
- return sb.ToString();
}
- static string[] ReservedWords = new string[]
- {
- // TODO: add SQLite reserved words here
- };
-
public override void EnsureCompatibility()
{
throw new NotImplementedException();
}
- public override T[] Select(System.Collections.Generic.IEnumerable filters)
+ public override T[] Select()
{
throw new NotImplementedException();
}
- public override object[] Select(Type entityType)
+ public override T[] Select(bool fillReferences)
{
throw new NotImplementedException();
}
- public override T[] Select(bool fillReferences)
+ public override T Select(object primaryKey)
{
throw new NotImplementedException();
}
@@ -317,21 +311,41 @@ public override T Select(object primaryKey, bool fillReferences)
throw new NotImplementedException();
}
+ public override T[] Select(string searchFieldName, object matchValue)
+ {
+ throw new NotImplementedException();
+ }
+
public override T[] Select(string searchFieldName, object matchValue, bool fillReferences)
{
throw new NotImplementedException();
}
+ public override T[] Select(System.Collections.Generic.IEnumerable filters)
+ {
+ throw new NotImplementedException();
+ }
+
public override T[] Select(System.Collections.Generic.IEnumerable filters, bool fillReferences)
{
throw new NotImplementedException();
}
+ public override object[] Select(Type entityType)
+ {
+ throw new NotImplementedException();
+ }
+
public override object[] Select(Type entityType, bool fillReferences)
{
throw new NotImplementedException();
}
+ public override void Update(object item)
+ {
+ throw new NotImplementedException();
+ }
+
public override void Update(object item, bool cascadeUpdates, string fieldName)
{
throw new NotImplementedException();
@@ -342,6 +356,31 @@ public override void Update(object item, string fieldName)
throw new NotImplementedException();
}
+ public override void Delete(object item)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void Delete(object primaryKey)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void FillReferences(object instance)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override T[] Fetch(int fetchCount)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override T[] Fetch(int fetchCount, int firstRowOffset)
+ {
+ throw new NotImplementedException();
+ }
+
public override T[] Fetch(int fetchCount, int firstRowOffset, string sortField)
{
throw new NotImplementedException();
@@ -352,9 +391,30 @@ public override T[] Fetch(int fetchCount, int firstRowOffset, string sortFiel
throw new NotImplementedException();
}
+ public override int Count()
+ {
+ throw new NotImplementedException();
+ }
+
public override int Count(System.Collections.Generic.IEnumerable filters)
{
throw new NotImplementedException();
}
+
+ public override void Delete()
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void Delete(string fieldName, object matchValue)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override bool Contains(object item)
+ {
+ throw new NotImplementedException();
+ }
+
}
}
diff --git a/OpenNETCF.ORM.SQLite/SQLiteEntityInfo.cs b/OpenNETCF.ORM.SQLite/SQLiteEntityInfo.cs
index 9b71ed6..1a2398d 100644
--- a/OpenNETCF.ORM.SQLite/SQLiteEntityInfo.cs
+++ b/OpenNETCF.ORM.SQLite/SQLiteEntityInfo.cs
@@ -1,13 +1,5 @@
using System;
using System.Net;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Documents;
-using System.Windows.Ink;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Animation;
-using System.Windows.Shapes;
namespace OpenNETCF.ORM
{
diff --git a/OpenNETCF.ORM.SQLite/SQLiteException.cs b/OpenNETCF.ORM.SQLite/SQLiteException.cs
index 35a668b..a9da66e 100644
--- a/OpenNETCF.ORM.SQLite/SQLiteException.cs
+++ b/OpenNETCF.ORM.SQLite/SQLiteException.cs
@@ -1,13 +1,5 @@
using System;
using System.Net;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Documents;
-using System.Windows.Ink;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Animation;
-using System.Windows.Shapes;
namespace OpenNETCF.ORM.SQLite
{
diff --git a/OpenNETCF.ORM.SqlCE.Integration.Test/OpenNETCF.ORM.SqlCE.Integration.Test.csproj b/OpenNETCF.ORM.SqlCE.Integration.Test/OpenNETCF.ORM.SqlCE.Integration.Test.csproj
new file mode 100644
index 0000000..dbd4164
--- /dev/null
+++ b/OpenNETCF.ORM.SqlCE.Integration.Test/OpenNETCF.ORM.SqlCE.Integration.Test.csproj
@@ -0,0 +1,81 @@
+
+
+
+ Debug
+ AnyCPU
+
+
+ 2.0
+ {5A05D8DE-100E-4443-9FBA-BEA87A070732}
+ Library
+ Properties
+ OpenNETCF.ORM.SqlCE.Integration.Test
+ OpenNETCF.ORM.SqlCE.Integration.Test
+ v4.0
+ 512
+ {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ SAK
+ SAK
+ SAK
+ SAK
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+ 3.5
+
+
+
+
+
+
+
+
+
+ False
+
+
+
+
+
+
+
+
+
+
+
+ {B63F2DF8-E247-402D-A250-2514EF4A08FD}
+ OpenNETCF.ORM.SqlCe.FFx
+
+
+ {6E9C7DA3-AD60-4E44-9D3A-7BBD3A20D79F}
+ OpenNETCF.ORM.FFx
+
+
+
+
+
\ No newline at end of file
diff --git a/OpenNETCF.ORM.SqlCE.Integration.Test/OpenNETCF.ORM.SqlCE.Integration.Test.csproj.vspscc b/OpenNETCF.ORM.SqlCE.Integration.Test/OpenNETCF.ORM.SqlCE.Integration.Test.csproj.vspscc
new file mode 100644
index 0000000..feffdec
--- /dev/null
+++ b/OpenNETCF.ORM.SqlCE.Integration.Test/OpenNETCF.ORM.SqlCE.Integration.Test.csproj.vspscc
@@ -0,0 +1,10 @@
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = ""
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
+}
diff --git a/OpenNETCF.ORM.SqlCE.Integration.Test/Properties/AssemblyInfo.cs b/OpenNETCF.ORM.SqlCE.Integration.Test/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..b0b0162
--- /dev/null
+++ b/OpenNETCF.ORM.SqlCE.Integration.Test/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("OpenNETCF.ORM.SqlCE.Integration.Test")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("OpenNETCF.ORM.SqlCE.Integration.Test")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("2d9ff38c-8a55-4640-94db-5b1fc7f975ef")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenNETCF.ORM.SqlCE.Integration.Test/SqlCeDataStoreTest.cs b/OpenNETCF.ORM.SqlCE.Integration.Test/SqlCeDataStoreTest.cs
new file mode 100644
index 0000000..00cefcb
--- /dev/null
+++ b/OpenNETCF.ORM.SqlCE.Integration.Test/SqlCeDataStoreTest.cs
@@ -0,0 +1,46 @@
+using OpenNETCF.ORM;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System.Linq;
+
+namespace OpenNETCF.ORM.SqlCE.Integration.Test
+{
+ [TestClass()]
+ public class SqlCeDataStoreTest
+ {
+ public TestContext TestContext { get; set; }
+ [TestMethod()]
+ [DeploymentItem("OpenNETCF.ORM.SqlCe.dll")]
+ public void SelectTest()
+ {
+ var store = new SqlCeDataStore("test.sdf");
+ store.AddType();
+ store.CreateStore();
+
+ store.Insert(new TestItem("ItemA"));
+ store.Insert(new TestItem("ItemB"));
+ store.Insert(new TestItem("ItemC"));
+
+ var item = store.Select("Name", "ItemB").FirstOrDefault();
+ item = store.Select(2);
+ }
+ }
+
+ [Entity(KeyScheme=KeyScheme.Identity)]
+ public class TestItem
+ {
+ public TestItem()
+ {
+ }
+
+ public TestItem(string name)
+ {
+ Name = name;
+ }
+
+ [Field(IsPrimaryKey=true)]
+ int ID { get; set; }
+
+ [Field]
+ string Name { get; set; }
+ }
+}
diff --git a/OpenNETCF.ORM.SqlCE.Integration.Test/Test References/OpenNETCF.ORM.SqlCe.accessor b/OpenNETCF.ORM.SqlCE.Integration.Test/Test References/OpenNETCF.ORM.SqlCe.accessor
new file mode 100644
index 0000000..b17b8f3
--- /dev/null
+++ b/OpenNETCF.ORM.SqlCE.Integration.Test/Test References/OpenNETCF.ORM.SqlCe.accessor
@@ -0,0 +1,2 @@
+OpenNETCF.ORM.SqlCe.dll
+Desktop
diff --git a/OpenNETCF.ORM.SqlCe/SqlCeDataStore.cs b/OpenNETCF.ORM.SqlCe/SqlCeDataStore.cs
index ebded44..b5fdba3 100644
--- a/OpenNETCF.ORM.SqlCe/SqlCeDataStore.cs
+++ b/OpenNETCF.ORM.SqlCe/SqlCeDataStore.cs
@@ -19,14 +19,13 @@ public partial class SqlCeDataStore : SQLStoreBase
private int m_maxSize = 128; // Max Database Size defaults to 128MB
private Dictionary m_referenceCache = new Dictionary();
- private Dictionary m_serializerCache = new Dictionary();
- private Dictionary m_deserializerCache = new Dictionary();
private string Password { get; set; }
public string FileName { get; protected set; }
protected SqlCeDataStore()
+ : base()
{
UseCommandCache = true;
}
@@ -56,6 +55,11 @@ protected override DbCommand GetNewCommandObject()
return new SqlCeCommand();
}
+ protected override string AutoIncrementFieldIdentifier
+ {
+ get { return "IDENTITY"; }
+ }
+
///
/// Deletes the underlying DataStore
///
@@ -121,36 +125,6 @@ public override void EnsureCompatibility()
}
}
- private MethodInfo GetSerializer(Type itemType)
- {
- if (m_serializerCache.ContainsKey(itemType))
- {
- return m_serializerCache[itemType];
- }
-
- var serializer = itemType.GetMethod("Serialize", BindingFlags.Public | BindingFlags.Instance);
-
- if (serializer == null) return null;
-
- m_serializerCache.Add(itemType, serializer);
- return serializer;
- }
-
- private MethodInfo GetDeserializer(Type itemType)
- {
- if (m_deserializerCache.ContainsKey(itemType))
- {
- return m_deserializerCache[itemType];
- }
-
- var deserializer = itemType.GetMethod("Deserialize", BindingFlags.Public | BindingFlags.Instance);
-
- if (deserializer == null) return null;
-
- m_deserializerCache.Add(itemType, deserializer);
- return deserializer;
- }
-
///
/// Determines if the specified object already exists in the Store (by primary key value)
///
diff --git a/OpenNETCF.ORM/Extensions.cs b/OpenNETCF.ORM/Extensions.cs
index f086827..073724f 100644
--- a/OpenNETCF.ORM/Extensions.cs
+++ b/OpenNETCF.ORM/Extensions.cs
@@ -166,7 +166,7 @@ public static string ToSqlTypeString(this DbType type)
return "bigint";
case DbType.Int32:
case DbType.UInt32:
- return "int";
+ return "integer";
case DbType.Int16:
case DbType.UInt16:
return "smallint";
diff --git a/OpenNETCF.ORM/SQL Store Base/SQLStoreBase.cs b/OpenNETCF.ORM/SQL Store Base/SQLStoreBase.cs
index 26e77fc..486fc38 100644
--- a/OpenNETCF.ORM/SQL Store Base/SQLStoreBase.cs
+++ b/OpenNETCF.ORM/SQL Store Base/SQLStoreBase.cs
@@ -5,6 +5,7 @@
using System.Diagnostics;
using System.Data;
using System.Data.Common;
+using System.Reflection;
namespace OpenNETCF.ORM
{
@@ -13,10 +14,13 @@ public abstract class SQLStoreBase : DataStore, IDispo
{
private List m_indexNameCache = new List();
private DbConnection m_connection;
+ private Dictionary m_serializerCache = new Dictionary();
+ private Dictionary m_deserializerCache = new Dictionary();
public int DefaultStringFieldSize { get; set; }
public int DefaultNumericFieldPrecision { get; set; }
public int DefaultVarBinaryLength { get; set; }
+ protected abstract string AutoIncrementFieldIdentifier { get; }
public ConnectionBehavior ConnectionBehavior { get; set; }
@@ -429,7 +433,7 @@ protected virtual string GetFieldCreationAttributes(EntityAttribute attribute, F
{
case DbType.Int32:
case DbType.UInt32:
- sb.Append("IDENTITY ");
+ sb.Append(AutoIncrementFieldIdentifier + " ");
break;
case DbType.Guid:
sb.Append("ROWGUIDCOL ");
@@ -454,5 +458,34 @@ protected virtual string GetFieldCreationAttributes(EntityAttribute attribute, F
return sb.ToString();
}
+ protected virtual MethodInfo GetSerializer(Type itemType)
+ {
+ if (m_serializerCache.ContainsKey(itemType))
+ {
+ return m_serializerCache[itemType];
+ }
+
+ var serializer = itemType.GetMethod("Serialize", BindingFlags.Public | BindingFlags.Instance);
+
+ if (serializer == null) return null;
+
+ m_serializerCache.Add(itemType, serializer);
+ return serializer;
+ }
+
+ protected virtual MethodInfo GetDeserializer(Type itemType)
+ {
+ if (m_deserializerCache.ContainsKey(itemType))
+ {
+ return m_deserializerCache[itemType];
+ }
+
+ var deserializer = itemType.GetMethod("Deserialize", BindingFlags.Public | BindingFlags.Instance);
+
+ if (deserializer == null) return null;
+
+ m_deserializerCache.Add(itemType, deserializer);
+ return deserializer;
+ }
}
}
diff --git a/TraceAndTestImpact.testsettings b/TraceAndTestImpact.testsettings
new file mode 100644
index 0000000..3bf3433
--- /dev/null
+++ b/TraceAndTestImpact.testsettings
@@ -0,0 +1,21 @@
+
+
+ These are test settings for Trace and Test Impact.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file