From 9276fa101f02a3c2065574e22e703bc89a1f91e2 Mon Sep 17 00:00:00 2001 From: Igor Ralic Date: Sat, 4 Apr 2015 03:05:51 +0200 Subject: [PATCH 1/4] Support for composite primary keys --- src/SQLite.Net.Async/SQLiteAsyncConnection.cs | 8 +- src/SQLite.Net/Orm.cs | 4 +- src/SQLite.Net/SQLiteConnection.cs | 89 +++++++++++++------ src/SQLite.Net/TableMapping.cs | 12 ++- tests/CreateTableImplicitTest.cs | 56 ++++++------ tests/DeleteTest.cs | 71 ++++++++++++++- tests/InheritanceTest.cs | 2 +- 7 files changed, 172 insertions(+), 70 deletions(-) diff --git a/src/SQLite.Net.Async/SQLiteAsyncConnection.cs b/src/SQLite.Net.Async/SQLiteAsyncConnection.cs index 4ca26301e..10bd988c1 100755 --- a/src/SQLite.Net.Async/SQLiteAsyncConnection.cs +++ b/src/SQLite.Net.Async/SQLiteAsyncConnection.cs @@ -234,18 +234,18 @@ public Task CreateTablesAsync([NotNull] params Type[] types) } [PublicAPI] - public Task DeleteAsync([NotNull] object pk, CancellationToken cancellationToken = default (CancellationToken)) + public Task DeleteAsync([NotNull] Dictionary pks, CancellationToken cancellationToken = default (CancellationToken)) { - if (pk == null) + if (pks == null) { - throw new ArgumentNullException("pk"); + throw new ArgumentNullException("pks"); } return Task.Factory.StartNew(() => { var conn = GetConnection(); using (conn.Lock()) { - return conn.Delete(pk); + return conn.Delete(pks); } }, cancellationToken, _taskCreationOptions, _taskScheduler ?? TaskScheduler.Default); } diff --git a/src/SQLite.Net/Orm.cs b/src/SQLite.Net/Orm.cs index 3d851dd00..7bc55c25a 100755 --- a/src/SQLite.Net/Orm.cs +++ b/src/SQLite.Net/Orm.cs @@ -37,11 +37,11 @@ internal static class Orm public const string ImplicitIndexSuffix = "Id"; internal static string SqlDecl(TableMapping.Column p, bool storeDateTimeAsTicks, IBlobSerializer serializer, - IDictionary extraTypeMappings) + IDictionary extraTypeMappings, int primaryKeyCount = 0) { var decl = "\"" + p.Name + "\" " + SqlType(p, storeDateTimeAsTicks, serializer, extraTypeMappings) + " "; - if (p.IsPK) + if (p.IsPK && primaryKeyCount == 1) { decl += "primary key "; } diff --git a/src/SQLite.Net/SQLiteConnection.cs b/src/SQLite.Net/SQLiteConnection.cs index 8aad37d1a..c01c01081 100644 --- a/src/SQLite.Net/SQLiteConnection.cs +++ b/src/SQLite.Net/SQLiteConnection.cs @@ -367,7 +367,7 @@ public int CreateTable(Type ty, CreateFlags createFlags = CreateFlags.None) { var map = GetMapping(ty, createFlags); - var query = "create table if not exists \"" + map.TableName + "\"(\n"; + var query = new StringBuilder("create table if not exists \"").Append(map.TableName).Append("\"( \n"); var mapColumns = map.Columns; @@ -376,12 +376,25 @@ public int CreateTable(Type ty, CreateFlags createFlags = CreateFlags.None) throw new Exception("Table has no (public) columns"); } - var decls = mapColumns.Select(p => Orm.SqlDecl(p, StoreDateTimeAsTicks, Serializer, ExtraTypeMappings)); + var PKs = mapColumns.Where(c => c.IsPK).ToList(); + + var decls = mapColumns.Select(p => Orm.SqlDecl(p, StoreDateTimeAsTicks, Serializer, ExtraTypeMappings, PKs.Count)); var decl = string.Join(",\n", decls.ToArray()); - query += decl; - query += ")"; + query.Append(decl).Append(",\n"); - var count = Execute(query); + + if (PKs.Count > 1) + { + query.Append("primary key (").Append(string.Join(",", PKs.Select(pk => pk.Name))).Append(")"); + } + else + { + query.Remove(query.Length - 2, 2); + } + + query.Append(")"); + + var count = Execute(query.ToString()); if (count == 0) { @@ -535,6 +548,8 @@ private void MigrateTable(TableMapping map) var toBeAdded = new List(); + var PKscount = map.Columns.Where(c => c.IsPK).Count(); + foreach (var p in map.Columns) { var found = false; @@ -554,8 +569,13 @@ private void MigrateTable(TableMapping map) foreach (var p in toBeAdded) { + if (p.IsPK) + { + throw new NotSupportedException("The new column may not have a PRIMARY KEY constraint."); + } + var addCol = "alter table \"" + map.TableName + "\" add column " + - Orm.SqlDecl(p, StoreDateTimeAsTicks, Serializer, ExtraTypeMappings); + Orm.SqlDecl(p, StoreDateTimeAsTicks, Serializer, ExtraTypeMappings, PKscount); Execute(addCol); } } @@ -1440,9 +1460,16 @@ public int Insert(object obj, string extra, Type objType) var map = GetMapping(objType); - if (map.PK != null && map.PK.IsAutoGuid) + TableMapping.Column pk = null; + + if (map.PKs != null) + { + pk = map.PKs.FirstOrDefault(p => p.IsAutoGuid); + } + + if (pk != null) { - var prop = objType.GetRuntimeProperty(map.PK.PropertyName); + var prop = objType.GetRuntimeProperty(pk.PropertyName); if (prop != null) { if (prop.GetValue(obj, null).Equals(Guid.Empty)) @@ -1548,25 +1575,23 @@ public int Update(object obj, Type objType) var map = GetMapping(objType); - var pk = map.PK; + var pks = map.PKs; - if (pk == null) + if (pks == null || pks.Length == 0) { throw new NotSupportedException("Cannot update " + map.TableName + ": it has no PK"); } var cols = from p in map.Columns - where p != pk + where !pks.Any(pk => pk == p) select p; - var vals = from c in cols - select c.GetValue(obj); - var ps = new List(vals) - { - pk.GetValue(obj) - }; - var q = string.Format("update \"{0}\" set {1} where {2} = ? ", map.TableName, + var ps = (from c in cols + select c.GetValue(obj)).ToList(); + + ps.AddRange(pks.Select(pk=>pk.GetValue(obj))); + var q = string.Format("update \"{0}\" set {1} where {2}", map.TableName, string.Join(",", (from c in cols - select "\"" + c.Name + "\" = ? ").ToArray()), pk.Name); + select "\"" + c.Name + "\" = ? ").ToArray()), string.Join(" and ", pks.Select(pk => "\"" + pk.Name + "\" = ? "))); try { rowsAffected = Execute(q, ps.ToArray()); @@ -1631,13 +1656,15 @@ public int UpdateAll(IEnumerable objects, bool runInTransaction = true) public int Delete(object objectToDelete) { var map = GetMapping(objectToDelete.GetType()); - var pk = map.PK; - if (pk == null) + var pks = map.PKs; + if (pks == null || pks.Length == 0) { throw new NotSupportedException("Cannot delete " + map.TableName + ": it has no PK"); } - var q = string.Format("delete from \"{0}\" where \"{1}\" = ?", map.TableName, pk.Name); - return Execute(q, pk.GetValue(objectToDelete)); + var q = string.Format("delete from \"{0}\" where {1}", map.TableName, string.Join(" and ", pks.Select(pk => "\"" + pk.Name + "\" = ? "))); + var ps = (from pk in pks + select pk.GetValue(objectToDelete)).ToArray(); + return Execute(q, ps); } /// @@ -1653,16 +1680,22 @@ public int Delete(object objectToDelete) /// The type of object. /// [PublicAPI] - public int Delete(object primaryKey) + public int Delete(Dictionary PKs) { var map = GetMapping(typeof (T)); - var pk = map.PK; - if (pk == null) + var pks = map.PKs; + if (pks == null || pks.Length == 0) { throw new NotSupportedException("Cannot delete " + map.TableName + ": it has no PK"); } - var q = string.Format("delete from \"{0}\" where \"{1}\" = ?", map.TableName, pk.Name); - return Execute(q, primaryKey); + if (PKs.Keys.Except(pks.Select(p => p.Name)).Count() > 0) + { + throw new NotSupportedException("Cannot delete " + map.TableName + ": PKs mismatch. Make sure PK names are valid."); + } + var q = string.Format("delete from \"{0}\" where {1}", map.TableName, string.Join(" and ", PKs.Keys.Select(pk => "\"" + pk + "\" = ? "))); + var ps = (from pk in PKs.Values + select pk).ToArray(); + return Execute(q, ps); } /// diff --git a/src/SQLite.Net/TableMapping.cs b/src/SQLite.Net/TableMapping.cs index ae275e414..9350e5e72 100644 --- a/src/SQLite.Net/TableMapping.cs +++ b/src/SQLite.Net/TableMapping.cs @@ -57,23 +57,21 @@ public TableMapping(Type type, IEnumerable properties, CreateFlags } } Columns = cols.ToArray(); + PKs = Columns.Where(col => col.IsPK).ToArray(); foreach (var c in Columns) { if (c.IsAutoInc && c.IsPK) { _autoPk = c; } - if (c.IsPK) - { - PK = c; - } } HasAutoIncPK = _autoPk != null; - if (PK != null) + if (PKs.Length > 0) { - GetByPrimaryKeySql = string.Format("select * from \"{0}\" where \"{1}\" = ?", TableName, PK.Name); + string pksString = string.Join(",", PKs.Select(pk => pk.Name)); + GetByPrimaryKeySql = string.Format("select * from \"{0}\" where \"{1}\" = ?", TableName, pksString); } else { @@ -92,7 +90,7 @@ public TableMapping(Type type, IEnumerable properties, CreateFlags public Column[] Columns { get; private set; } [PublicAPI] - public Column PK { get; private set; } + public Column[] PKs { get; private set; } [PublicAPI] public string GetByPrimaryKeySql { get; private set; } diff --git a/tests/CreateTableImplicitTest.cs b/tests/CreateTableImplicitTest.cs index 5ef716755..a3c0d839a 100644 --- a/tests/CreateTableImplicitTest.cs +++ b/tests/CreateTableImplicitTest.cs @@ -51,10 +51,11 @@ public void ImplicitAutoInc() TableMapping mapping = db.GetMapping(); - Assert.IsNotNull(mapping.PK); - Assert.AreEqual("Id", mapping.PK.Name); - Assert.IsTrue(mapping.PK.IsPK); - Assert.IsTrue(mapping.PK.IsAutoInc); + Assert.IsNotNull(mapping.PKs); + Assert.IsNotEmpty(mapping.PKs); + Assert.AreEqual("Id", mapping.PKs[0].Name); + Assert.IsTrue(mapping.PKs[0].IsPK); + Assert.IsTrue(mapping.PKs[0].IsAutoInc); } [Test] @@ -66,10 +67,11 @@ public void ImplicitAutoIncAsPassedInTypes() TableMapping mapping = db.GetMapping(); - Assert.IsNotNull(mapping.PK); - Assert.AreEqual("Id", mapping.PK.Name); - Assert.IsTrue(mapping.PK.IsPK); - Assert.IsTrue(mapping.PK.IsAutoInc); + Assert.IsNotNull(mapping.PKs); + Assert.IsNotEmpty(mapping.PKs); + Assert.AreEqual("Id", mapping.PKs[0].Name); + Assert.IsTrue(mapping.PKs[0].IsPK); + Assert.IsTrue(mapping.PKs[0].IsAutoInc); } [Test] @@ -94,10 +96,11 @@ public void ImplicitPK() TableMapping mapping = db.GetMapping(); - Assert.IsNotNull(mapping.PK); - Assert.AreEqual("Id", mapping.PK.Name); - Assert.IsTrue(mapping.PK.IsPK); - Assert.IsFalse(mapping.PK.IsAutoInc); + Assert.IsNotNull(mapping.PKs); + Assert.IsNotEmpty(mapping.PKs); + Assert.AreEqual("Id", mapping.PKs[0].Name); + Assert.IsTrue(mapping.PKs[0].IsPK); + Assert.IsFalse(mapping.PKs[0].IsAutoInc); CheckPK(db); } @@ -111,10 +114,11 @@ public void ImplicitPKAutoInc() TableMapping mapping = db.GetMapping(); - Assert.IsNotNull(mapping.PK); - Assert.AreEqual("Id", mapping.PK.Name); - Assert.IsTrue(mapping.PK.IsPK); - Assert.IsTrue(mapping.PK.IsAutoInc); + Assert.IsNotNull(mapping.PKs); + Assert.IsNotEmpty(mapping.PKs); + Assert.AreEqual("Id", mapping.PKs[0].Name); + Assert.IsTrue(mapping.PKs[0].IsPK); + Assert.IsTrue(mapping.PKs[0].IsAutoInc); } [Test] @@ -126,10 +130,11 @@ public void ImplicitPKAutoIncAsPassedInTypes() TableMapping mapping = db.GetMapping(); - Assert.IsNotNull(mapping.PK); - Assert.AreEqual("Id", mapping.PK.Name); - Assert.IsTrue(mapping.PK.IsPK); - Assert.IsTrue(mapping.PK.IsAutoInc); + Assert.IsNotNull(mapping.PKs); + Assert.IsNotEmpty(mapping.PKs); + Assert.AreEqual("Id", mapping.PKs[0].Name); + Assert.IsTrue(mapping.PKs[0].IsPK); + Assert.IsTrue(mapping.PKs[0].IsAutoInc); } [Test] @@ -141,10 +146,11 @@ public void ImplicitPkAsPassedInTypes() TableMapping mapping = db.GetMapping(); - Assert.IsNotNull(mapping.PK); - Assert.AreEqual("Id", mapping.PK.Name); - Assert.IsTrue(mapping.PK.IsPK); - Assert.IsFalse(mapping.PK.IsAutoInc); + Assert.IsNotNull(mapping.PKs); + Assert.IsNotEmpty(mapping.PKs); + Assert.AreEqual("Id", mapping.PKs[0].Name); + Assert.IsTrue(mapping.PKs[0].IsPK); + Assert.IsFalse(mapping.PKs[0].IsAutoInc); } [Test] @@ -156,7 +162,7 @@ public void WithoutImplicitMapping() TableMapping mapping = db.GetMapping(); - Assert.IsNull(mapping.PK); + Assert.IsEmpty(mapping.PKs); TableMapping.Column column = mapping.Columns[2]; Assert.AreEqual("IndexedId", column.Name); diff --git a/tests/DeleteTest.cs b/tests/DeleteTest.cs index 49967e08a..a760cd39d 100644 --- a/tests/DeleteTest.cs +++ b/tests/DeleteTest.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Linq; using NUnit.Framework; using SQLite.Net.Attributes; @@ -16,12 +17,27 @@ private class TestTable public string Test { get; set; } } + private class TestTableCompositeKey + { + [PrimaryKey] + public int Id { get; set; } + + [PrimaryKey] + public int TestIndex { get; set; } + + public int Datum { get; set; } + public string Test { get; set; } + } + private const int Count = 100; private SQLiteConnection CreateDb() { var db = new TestDb(); + db.CreateTable(); + db.CreateTable(); + var items = from i in Enumerable.Range(0, Count) select new TestTable @@ -31,7 +47,20 @@ from i in Enumerable.Range(0, Count) } ; db.InsertAll(items); - Assert.AreEqual(Count, db.Table().Count()); + + var itemsCompositeKey = + from i in Enumerable.Range(0, Count) + select new TestTableCompositeKey + { + Datum = 1000 + i, + Test = "Hello World", + Id = i, + TestIndex = i + 1 + } + ; + db.InsertAll(itemsCompositeKey); + Assert.AreEqual(Count, db.Table().Count()); + return db; } @@ -89,7 +118,10 @@ public void DeletePKNone() { var db = CreateDb(); - var r = db.Delete(348597); + var pks = new Dictionary(); + pks.Add("Id", 348597); + + var r = db.Delete(pks); Assert.AreEqual(0, r); Assert.AreEqual(Count, db.Table().Count()); @@ -100,10 +132,43 @@ public void DeletePKOne() { var db = CreateDb(); - var r = db.Delete(1); + var pks = new Dictionary(); + pks.Add("Id", 1); + + var r = db.Delete(pks); Assert.AreEqual(1, r); Assert.AreEqual(Count - 1, db.Table().Count()); } + + [Test] + public void DeletePKNoneComposite() + { + var db = CreateDb(); + + var pks = new Dictionary(); + pks.Add("Id", 348597); + pks.Add("TestIndex", 348598); + + var r = db.Delete(pks); + + Assert.AreEqual(0, r); + Assert.AreEqual(Count, db.Table().Count()); + } + + [Test] + public void DeletePKOneComposite() + { + var db = CreateDb(); + + var pks = new Dictionary(); + pks.Add("Id", 1); + pks.Add("TestIndex", 2); + + var r = db.Delete(pks); + + Assert.AreEqual(1, r); + Assert.AreEqual(Count - 1, db.Table().Count()); + } } } \ No newline at end of file diff --git a/tests/InheritanceTest.cs b/tests/InheritanceTest.cs index 6b9734084..8455bb1e7 100644 --- a/tests/InheritanceTest.cs +++ b/tests/InheritanceTest.cs @@ -28,7 +28,7 @@ public void InheritanceWorks() TableMapping mapping = db.GetMapping(); Assert.AreEqual(3, mapping.Columns.Length); - Assert.AreEqual("Id", mapping.PK.Name); + Assert.AreEqual("Id", mapping.PKs[0].Name); } } } \ No newline at end of file From b090ab2b1ec9589dc5e175e54e7f781039fc5452 Mon Sep 17 00:00:00 2001 From: Igor Ralic Date: Mon, 6 Apr 2015 17:56:54 +0200 Subject: [PATCH 2/4] Update to support composite primary key in Find, Get and Delete methods without changing the method signature --- src/SQLite.Net.Async/SQLiteAsyncConnection.cs | 8 +- src/SQLite.Net/SQLiteConnection.cs | 107 +++++++++++++++--- src/SQLite.Net/TableMapping.cs | 33 ++++-- tests/DeleteTest.cs | 10 +- 4 files changed, 123 insertions(+), 35 deletions(-) diff --git a/src/SQLite.Net.Async/SQLiteAsyncConnection.cs b/src/SQLite.Net.Async/SQLiteAsyncConnection.cs index 10bd988c1..4ca26301e 100755 --- a/src/SQLite.Net.Async/SQLiteAsyncConnection.cs +++ b/src/SQLite.Net.Async/SQLiteAsyncConnection.cs @@ -234,18 +234,18 @@ public Task CreateTablesAsync([NotNull] params Type[] types) } [PublicAPI] - public Task DeleteAsync([NotNull] Dictionary pks, CancellationToken cancellationToken = default (CancellationToken)) + public Task DeleteAsync([NotNull] object pk, CancellationToken cancellationToken = default (CancellationToken)) { - if (pks == null) + if (pk == null) { - throw new ArgumentNullException("pks"); + throw new ArgumentNullException("pk"); } return Task.Factory.StartNew(() => { var conn = GetConnection(); using (conn.Lock()) { - return conn.Delete(pks); + return conn.Delete(pk); } }, cancellationToken, _taskCreationOptions, _taskScheduler ?? TaskScheduler.Default); } diff --git a/src/SQLite.Net/SQLiteConnection.cs b/src/SQLite.Net/SQLiteConnection.cs index c01c01081..5e0398748 100644 --- a/src/SQLite.Net/SQLiteConnection.cs +++ b/src/SQLite.Net/SQLiteConnection.cs @@ -814,7 +814,7 @@ public TableQuery Table() where T : class /// the given type have a designated PrimaryKey (using the PrimaryKeyAttribute). /// /// - /// The primary key. + /// The primary key. Needs to be Dictionary if table has composite PK. /// /// /// The object with the given primary key. Throws a not found exception @@ -824,7 +824,28 @@ public TableQuery Table() where T : class public T Get(object pk) where T : class { var map = GetMapping(typeof (T)); - return Query(map.GetByPrimaryKeySql, pk).First(); + if (map.HasCompositePK) + { + IDictionary PKs = pk as Dictionary; + if (PKs == null) + { + throw new NotSupportedException(map.TableName + " table has a composite primary key. Make sure primary key is passed in as Dictionary."); + } + var pks = map.PKs; + if (pks == null || pks.Length == 0) + { + throw new NotSupportedException("Cannot get from " + map.TableName + ": it has no PK"); + } + if (PKs.Keys.Intersect(pks.Select(p => p.Name)).Count() < pks.Length) + { + throw new NotSupportedException("Cannot get from " + map.TableName + ": PKs mismatch. Make sure PK names are valid."); + } + return Query(map.GetByPrimaryKeySql, PKs.Values.ToArray()).First(); + } + else + { + return Query(map.GetByPrimaryKeySql, pk).First(); + } } /// @@ -850,7 +871,7 @@ public T Get(Expression> predicate) where T : class /// the given type have a designated PrimaryKey (using the PrimaryKeyAttribute). /// /// - /// The primary key. + /// The primary key. Needs to be Dictionary if table has composite PK. /// /// /// The object with the given primary key or null @@ -859,8 +880,29 @@ public T Get(Expression> predicate) where T : class [PublicAPI] public T Find(object pk) where T : class { - var map = GetMapping(typeof (T)); - return Query(map.GetByPrimaryKeySql, pk).FirstOrDefault(); + var map = GetMapping(typeof(T)); + if (map.HasCompositePK) + { + IDictionary PKs = pk as Dictionary; + if (PKs == null) + { + throw new NotSupportedException(map.TableName + " table has a composite primary key. Make sure primary key is passed in as Dictionary."); + } + var pks = map.PKs; + if (pks == null || pks.Length == 0) + { + throw new NotSupportedException("Cannot find in " + map.TableName + ": it has no PK"); + } + if (PKs.Keys.Intersect(pks.Select(p => p.Name)).Count() < pks.Length) + { + throw new NotSupportedException("Cannot find in " + map.TableName + ": PKs mismatch. Make sure PK names are valid."); + } + return Query(map.GetByPrimaryKeySql, PKs.Values.ToArray()).FirstOrDefault(); + } + else + { + return Query(map.GetByPrimaryKeySql, pk).FirstOrDefault(); + } } /// @@ -889,7 +931,7 @@ public T FindWithQuery(string query, params object[] args) where T : class /// the given type have a designated PrimaryKey (using the PrimaryKeyAttribute). /// /// - /// The primary key. + /// The primary key. Needs to be Dictionary if table has composite PK. /// /// /// The TableMapping used to identify the object type. @@ -901,7 +943,28 @@ public T FindWithQuery(string query, params object[] args) where T : class [PublicAPI] public object Find(object pk, TableMapping map) { - return Query(map, map.GetByPrimaryKeySql, pk).FirstOrDefault(); + if (map.HasCompositePK) + { + IDictionary PKs = pk as Dictionary; + if (PKs == null) + { + throw new NotSupportedException(map.TableName + " table has a composite primary key. Make sure primary key is passed in as Dictionary."); + } + var pks = map.PKs; + if (pks == null || pks.Length == 0) + { + throw new NotSupportedException("Cannot find in " + map.TableName + ": it has no PK"); + } + if (PKs.Keys.Intersect(pks.Select(p => p.Name)).Count() < pks.Length) + { + throw new NotSupportedException("Cannot find in " + map.TableName + ": PKs mismatch. Make sure PK names are valid."); + } + return Query(map, map.GetByPrimaryKeySql, PKs.Values.ToArray()).FirstOrDefault(); + } + else + { + return Query(map, map.GetByPrimaryKeySql, pk).FirstOrDefault(); + } } /// @@ -1671,7 +1734,7 @@ public int Delete(object objectToDelete) /// Deletes the object with the specified primary key. /// /// - /// The primary key of the object to delete. + /// The primary key of the object to delete. Needs to be Dictionary if table has composite PK. /// /// /// The number of objects deleted. @@ -1680,7 +1743,7 @@ public int Delete(object objectToDelete) /// The type of object. /// [PublicAPI] - public int Delete(Dictionary PKs) + public int Delete(object primaryKey) { var map = GetMapping(typeof (T)); var pks = map.PKs; @@ -1688,14 +1751,28 @@ public int Delete(Dictionary PKs) { throw new NotSupportedException("Cannot delete " + map.TableName + ": it has no PK"); } - if (PKs.Keys.Except(pks.Select(p => p.Name)).Count() > 0) + + if (map.HasCompositePK) + { + IDictionary PKs = primaryKey as Dictionary; + if (PKs == null) + { + throw new NotSupportedException(map.TableName + " table has a composite primary key. Make sure primary key is passed in as Dictionary."); + } + if (PKs.Keys.Intersect(pks.Select(p => p.Name)).Count() < pks.Length) + { + throw new NotSupportedException("Cannot delete " + map.TableName + ": PKs mismatch. Make sure PK names are valid."); + } + var q = string.Format("delete from \"{0}\" where {1}", map.TableName, string.Join(" and ", PKs.Keys.Select(pk => "\"" + pk + "\" = ? "))); + var ps = (from pk in PKs.Values + select pk).ToArray(); + return Execute(q, ps); + } + else { - throw new NotSupportedException("Cannot delete " + map.TableName + ": PKs mismatch. Make sure PK names are valid."); + var q = string.Format("delete from \"{0}\" where \"{1}\" = ?", map.TableName, pks.FirstOrDefault().Name); + return Execute(q, primaryKey); } - var q = string.Format("delete from \"{0}\" where {1}", map.TableName, string.Join(" and ", PKs.Keys.Select(pk => "\"" + pk + "\" = ? "))); - var ps = (from pk in PKs.Values - select pk).ToArray(); - return Execute(q, ps); } /// diff --git a/src/SQLite.Net/TableMapping.cs b/src/SQLite.Net/TableMapping.cs index 9350e5e72..877f61a21 100644 --- a/src/SQLite.Net/TableMapping.cs +++ b/src/SQLite.Net/TableMapping.cs @@ -58,20 +58,34 @@ public TableMapping(Type type, IEnumerable properties, CreateFlags } Columns = cols.ToArray(); PKs = Columns.Where(col => col.IsPK).ToArray(); - foreach (var c in Columns) + + if (PKs.Length > 1) + { + HasCompositePK = true; + } + + if (!HasCompositePK) { - if (c.IsAutoInc && c.IsPK) + foreach (var c in Columns) { - _autoPk = c; + if (c.IsAutoInc && c.IsPK) + { + _autoPk = c; + } } - } - HasAutoIncPK = _autoPk != null; + HasAutoIncPK = _autoPk != null; + } - if (PKs.Length > 0) + if (PKs.Length > 1) + { + string pksString = string.Join(" and ", PKs.Select(pk => "\"" + pk.Name + "\" = ? ")); + GetByPrimaryKeySql = string.Format("select * from \"{0}\" where {1}", TableName, pksString); + } + else if (PKs.Length == 1) { - string pksString = string.Join(",", PKs.Select(pk => pk.Name)); - GetByPrimaryKeySql = string.Format("select * from \"{0}\" where \"{1}\" = ?", TableName, pksString); + string pkString = PKs.FirstOrDefault().Name; + GetByPrimaryKeySql = string.Format("select * from \"{0}\" where \"{1}\" = ?", TableName, pkString); } else { @@ -98,6 +112,9 @@ public TableMapping(Type type, IEnumerable properties, CreateFlags [PublicAPI] public bool HasAutoIncPK { get; private set; } + [PublicAPI] + public bool HasCompositePK { get; private set; } + [PublicAPI] public Column[] InsertColumns { diff --git a/tests/DeleteTest.cs b/tests/DeleteTest.cs index a760cd39d..251c02fcd 100644 --- a/tests/DeleteTest.cs +++ b/tests/DeleteTest.cs @@ -118,10 +118,7 @@ public void DeletePKNone() { var db = CreateDb(); - var pks = new Dictionary(); - pks.Add("Id", 348597); - - var r = db.Delete(pks); + var r = db.Delete(348597); Assert.AreEqual(0, r); Assert.AreEqual(Count, db.Table().Count()); @@ -132,10 +129,7 @@ public void DeletePKOne() { var db = CreateDb(); - var pks = new Dictionary(); - pks.Add("Id", 1); - - var r = db.Delete(pks); + var r = db.Delete(1); Assert.AreEqual(1, r); Assert.AreEqual(Count - 1, db.Table().Count()); From 75d3cfb9dfcbd31727990d46a1a802b91b96bceb Mon Sep 17 00:00:00 2001 From: Igor Ralic Date: Sat, 11 Apr 2015 14:56:07 +0200 Subject: [PATCH 3/4] Keep both PK and composite PK as a part of TableMapping public API. --- src/SQLite.Net/Orm.cs | 4 +- src/SQLite.Net/SQLiteConnection.cs | 141 ++++++++++++++++++----------- src/SQLite.Net/TableMapping.cs | 22 +++++ tests/CreateTableImplicitTest.cs | 63 ++++++------- tests/InheritanceTest.cs | 2 +- 5 files changed, 146 insertions(+), 86 deletions(-) diff --git a/src/SQLite.Net/Orm.cs b/src/SQLite.Net/Orm.cs index 7bc55c25a..bdea44225 100755 --- a/src/SQLite.Net/Orm.cs +++ b/src/SQLite.Net/Orm.cs @@ -37,11 +37,11 @@ internal static class Orm public const string ImplicitIndexSuffix = "Id"; internal static string SqlDecl(TableMapping.Column p, bool storeDateTimeAsTicks, IBlobSerializer serializer, - IDictionary extraTypeMappings, int primaryKeyCount = 0) + IDictionary extraTypeMappings, bool hasCompositePK = false) { var decl = "\"" + p.Name + "\" " + SqlType(p, storeDateTimeAsTicks, serializer, extraTypeMappings) + " "; - if (p.IsPK && primaryKeyCount == 1) + if (p.IsPK && !hasCompositePK) { decl += "primary key "; } diff --git a/src/SQLite.Net/SQLiteConnection.cs b/src/SQLite.Net/SQLiteConnection.cs index 5e0398748..86a64cfcb 100644 --- a/src/SQLite.Net/SQLiteConnection.cs +++ b/src/SQLite.Net/SQLiteConnection.cs @@ -376,24 +376,23 @@ public int CreateTable(Type ty, CreateFlags createFlags = CreateFlags.None) throw new Exception("Table has no (public) columns"); } - var PKs = mapColumns.Where(c => c.IsPK).ToList(); - - var decls = mapColumns.Select(p => Orm.SqlDecl(p, StoreDateTimeAsTicks, Serializer, ExtraTypeMappings, PKs.Count)); - var decl = string.Join(",\n", decls.ToArray()); - query.Append(decl).Append(",\n"); - - - if (PKs.Count > 1) + if (map.HasCompositePK) { + var PKs = mapColumns.Where(c => c.IsPK).ToList(); + + var decls = mapColumns.Select(p => Orm.SqlDecl(p, StoreDateTimeAsTicks, Serializer, ExtraTypeMappings, map.HasCompositePK)); + var decl = string.Join(",\n", decls.ToArray()); + query.Append(decl).Append(",\n"); query.Append("primary key (").Append(string.Join(",", PKs.Select(pk => pk.Name))).Append(")"); + query.Append(")"); } else { - query.Remove(query.Length - 2, 2); + var decls = mapColumns.Select(p => Orm.SqlDecl(p, StoreDateTimeAsTicks, Serializer, ExtraTypeMappings)); + var decl = string.Join(",\n", decls.ToArray()); + query.Append(decl).Append(")"); } - query.Append(")"); - var count = Execute(query.ToString()); if (count == 0) @@ -575,7 +574,7 @@ private void MigrateTable(TableMapping map) } var addCol = "alter table \"" + map.TableName + "\" add column " + - Orm.SqlDecl(p, StoreDateTimeAsTicks, Serializer, ExtraTypeMappings, PKscount); + Orm.SqlDecl(p, StoreDateTimeAsTicks, Serializer, ExtraTypeMappings, map.HasCompositePK); Execute(addCol); } } @@ -832,10 +831,6 @@ public T Get(object pk) where T : class throw new NotSupportedException(map.TableName + " table has a composite primary key. Make sure primary key is passed in as Dictionary."); } var pks = map.PKs; - if (pks == null || pks.Length == 0) - { - throw new NotSupportedException("Cannot get from " + map.TableName + ": it has no PK"); - } if (PKs.Keys.Intersect(pks.Select(p => p.Name)).Count() < pks.Length) { throw new NotSupportedException("Cannot get from " + map.TableName + ": PKs mismatch. Make sure PK names are valid."); @@ -889,10 +884,6 @@ public T Find(object pk) where T : class throw new NotSupportedException(map.TableName + " table has a composite primary key. Make sure primary key is passed in as Dictionary."); } var pks = map.PKs; - if (pks == null || pks.Length == 0) - { - throw new NotSupportedException("Cannot find in " + map.TableName + ": it has no PK"); - } if (PKs.Keys.Intersect(pks.Select(p => p.Name)).Count() < pks.Length) { throw new NotSupportedException("Cannot find in " + map.TableName + ": PKs mismatch. Make sure PK names are valid."); @@ -951,10 +942,6 @@ public object Find(object pk, TableMapping map) throw new NotSupportedException(map.TableName + " table has a composite primary key. Make sure primary key is passed in as Dictionary."); } var pks = map.PKs; - if (pks == null || pks.Length == 0) - { - throw new NotSupportedException("Cannot find in " + map.TableName + ": it has no PK"); - } if (PKs.Keys.Intersect(pks.Select(p => p.Name)).Count() < pks.Length) { throw new NotSupportedException("Cannot find in " + map.TableName + ": PKs mismatch. Make sure PK names are valid."); @@ -1522,13 +1509,19 @@ public int Insert(object obj, string extra, Type objType) } var map = GetMapping(objType); - TableMapping.Column pk = null; - if (map.PKs != null) + if (map.HasCompositePK) { pk = map.PKs.FirstOrDefault(p => p.IsAutoGuid); } + else + { + if (map.PK != null && map.PK.IsAutoGuid) + { + pk = map.PK; + } + } if (pk != null) { @@ -1637,27 +1630,57 @@ public int Update(object obj, Type objType) } var map = GetMapping(objType); + string q = null; + object[] ps = null; - var pks = map.PKs; - - if (pks == null || pks.Length == 0) + if (map.HasCompositePK) { - throw new NotSupportedException("Cannot update " + map.TableName + ": it has no PK"); + var pks = map.PKs; + var cols = from p in map.Columns + where !pks.Any(pk => pk == p) + select p; + + var pslist = (from c in cols + select c.GetValue(obj)).ToList(); + + pslist.AddRange(pks.Select(pk => pk.GetValue(obj))); + + q = string.Format("update \"{0}\" set {1} where {2}", map.TableName, + string.Join(",", (from c in cols + select "\"" + c.Name + "\" = ? ").ToArray()), string.Join(" and ", pks.Select(pk => "\"" + pk.Name + "\" = ? "))); + + ps = pslist.ToArray(); } + else + { + var pk = map.PK; - var cols = from p in map.Columns - where !pks.Any(pk => pk == p) - select p; - var ps = (from c in cols - select c.GetValue(obj)).ToList(); + if (pk == null) + { + throw new NotSupportedException("Cannot update " + map.TableName + ": it has no PK"); + } + + var cols = from p in map.Columns + where p != pk + select p; + + var vals = from c in cols + select c.GetValue(obj); + var pslist = new List(vals) + { + pk.GetValue(obj) + }; + + q = string.Format("update \"{0}\" set {1} where {2} = ? ", map.TableName, + string.Join(",", (from c in cols + select "\"" + c.Name + "\" = ? ").ToArray()), pk.Name); + + ps = pslist.ToArray(); + } - ps.AddRange(pks.Select(pk=>pk.GetValue(obj))); - var q = string.Format("update \"{0}\" set {1} where {2}", map.TableName, - string.Join(",", (from c in cols - select "\"" + c.Name + "\" = ? ").ToArray()), string.Join(" and ", pks.Select(pk => "\"" + pk.Name + "\" = ? "))); try { - rowsAffected = Execute(q, ps.ToArray()); + rowsAffected = Execute(q, ps); } catch (SQLiteException ex) { @@ -1719,14 +1742,27 @@ public int UpdateAll(IEnumerable objects, bool runInTransaction = true) public int Delete(object objectToDelete) { var map = GetMapping(objectToDelete.GetType()); - var pks = map.PKs; - if (pks == null || pks.Length == 0) + string q = null; + object[] ps = null; + + if (map.HasCompositePK) { - throw new NotSupportedException("Cannot delete " + map.TableName + ": it has no PK"); - } - var q = string.Format("delete from \"{0}\" where {1}", map.TableName, string.Join(" and ", pks.Select(pk => "\"" + pk.Name + "\" = ? "))); - var ps = (from pk in pks + var pks = map.PKs; + q = string.Format("delete from \"{0}\" where {1}", map.TableName, string.Join(" and ", pks.Select(pk => "\"" + pk.Name + "\" = ? "))); + ps = (from pk in pks select pk.GetValue(objectToDelete)).ToArray(); + } + else + { + var pk = map.PK; + if (pk == null) + { + throw new NotSupportedException("Cannot delete " + map.TableName + ": it has no PK"); + } + q = string.Format("delete from \"{0}\" where \"{1}\" = ?", map.TableName, pk.Name); + ps = new object[] { pk.GetValue(objectToDelete) }; + } + return Execute(q, ps); } @@ -1746,14 +1782,10 @@ public int Delete(object objectToDelete) public int Delete(object primaryKey) { var map = GetMapping(typeof (T)); - var pks = map.PKs; - if (pks == null || pks.Length == 0) - { - throw new NotSupportedException("Cannot delete " + map.TableName + ": it has no PK"); - } if (map.HasCompositePK) { + var pks = map.PKs; IDictionary PKs = primaryKey as Dictionary; if (PKs == null) { @@ -1770,7 +1802,12 @@ public int Delete(object primaryKey) } else { - var q = string.Format("delete from \"{0}\" where \"{1}\" = ?", map.TableName, pks.FirstOrDefault().Name); + var pk = map.PK; + if (pk == null) + { + throw new NotSupportedException("Cannot delete " + map.TableName + ": it has no PK"); + } + var q = string.Format("delete from \"{0}\" where \"{1}\" = ?", map.TableName, pk.Name); return Execute(q, primaryKey); } } diff --git a/src/SQLite.Net/TableMapping.cs b/src/SQLite.Net/TableMapping.cs index 877f61a21..fadbadb13 100644 --- a/src/SQLite.Net/TableMapping.cs +++ b/src/SQLite.Net/TableMapping.cs @@ -34,6 +34,7 @@ public class TableMapping { private readonly Column _autoPk; private Column[] _insertColumns; + private Column _pk; [PublicAPI] public TableMapping(Type type, IEnumerable properties, CreateFlags createFlags = CreateFlags.None) @@ -72,6 +73,11 @@ public TableMapping(Type type, IEnumerable properties, CreateFlags { _autoPk = c; } + + if (c.IsPK) + { + _pk = c; + } } HasAutoIncPK = _autoPk != null; @@ -103,6 +109,22 @@ public TableMapping(Type type, IEnumerable properties, CreateFlags [PublicAPI] public Column[] Columns { get; private set; } + [PublicAPI] + public Column PK + { + get + { + if (HasCompositePK) + { + throw new NotSupportedException("Table has a composite primary key. Use PKs property instead."); + } + else + { + return _pk; + } + } + } + [PublicAPI] public Column[] PKs { get; private set; } diff --git a/tests/CreateTableImplicitTest.cs b/tests/CreateTableImplicitTest.cs index a3c0d839a..13079a3d3 100644 --- a/tests/CreateTableImplicitTest.cs +++ b/tests/CreateTableImplicitTest.cs @@ -51,11 +51,11 @@ public void ImplicitAutoInc() TableMapping mapping = db.GetMapping(); - Assert.IsNotNull(mapping.PKs); - Assert.IsNotEmpty(mapping.PKs); - Assert.AreEqual("Id", mapping.PKs[0].Name); - Assert.IsTrue(mapping.PKs[0].IsPK); - Assert.IsTrue(mapping.PKs[0].IsAutoInc); + Assert.IsFalse(mapping.HasCompositePK); + Assert.IsNotNull(mapping.PK); + Assert.AreEqual("Id", mapping.PK.Name); + Assert.IsTrue(mapping.PK.IsPK); + Assert.IsTrue(mapping.PK.IsAutoInc); } [Test] @@ -67,11 +67,11 @@ public void ImplicitAutoIncAsPassedInTypes() TableMapping mapping = db.GetMapping(); - Assert.IsNotNull(mapping.PKs); - Assert.IsNotEmpty(mapping.PKs); - Assert.AreEqual("Id", mapping.PKs[0].Name); - Assert.IsTrue(mapping.PKs[0].IsPK); - Assert.IsTrue(mapping.PKs[0].IsAutoInc); + Assert.IsFalse(mapping.HasCompositePK); + Assert.IsNotNull(mapping.PK); + Assert.AreEqual("Id", mapping.PK.Name); + Assert.IsTrue(mapping.PK.IsPK); + Assert.IsTrue(mapping.PK.IsAutoInc); } [Test] @@ -96,11 +96,11 @@ public void ImplicitPK() TableMapping mapping = db.GetMapping(); - Assert.IsNotNull(mapping.PKs); - Assert.IsNotEmpty(mapping.PKs); - Assert.AreEqual("Id", mapping.PKs[0].Name); - Assert.IsTrue(mapping.PKs[0].IsPK); - Assert.IsFalse(mapping.PKs[0].IsAutoInc); + Assert.IsFalse(mapping.HasCompositePK); + Assert.IsNotNull(mapping.PK); + Assert.AreEqual("Id", mapping.PK.Name); + Assert.IsTrue(mapping.PK.IsPK); + Assert.IsFalse(mapping.PK.IsAutoInc); CheckPK(db); } @@ -114,11 +114,11 @@ public void ImplicitPKAutoInc() TableMapping mapping = db.GetMapping(); - Assert.IsNotNull(mapping.PKs); - Assert.IsNotEmpty(mapping.PKs); - Assert.AreEqual("Id", mapping.PKs[0].Name); - Assert.IsTrue(mapping.PKs[0].IsPK); - Assert.IsTrue(mapping.PKs[0].IsAutoInc); + Assert.IsFalse(mapping.HasCompositePK); + Assert.IsNotNull(mapping.PK); + Assert.AreEqual("Id", mapping.PK.Name); + Assert.IsTrue(mapping.PK.IsPK); + Assert.IsTrue(mapping.PK.IsAutoInc); } [Test] @@ -130,11 +130,11 @@ public void ImplicitPKAutoIncAsPassedInTypes() TableMapping mapping = db.GetMapping(); - Assert.IsNotNull(mapping.PKs); - Assert.IsNotEmpty(mapping.PKs); - Assert.AreEqual("Id", mapping.PKs[0].Name); - Assert.IsTrue(mapping.PKs[0].IsPK); - Assert.IsTrue(mapping.PKs[0].IsAutoInc); + Assert.IsFalse(mapping.HasCompositePK); + Assert.IsNotNull(mapping.PK); + Assert.AreEqual("Id", mapping.PK.Name); + Assert.IsTrue(mapping.PK.IsPK); + Assert.IsTrue(mapping.PK.IsAutoInc); } [Test] @@ -146,11 +146,11 @@ public void ImplicitPkAsPassedInTypes() TableMapping mapping = db.GetMapping(); - Assert.IsNotNull(mapping.PKs); - Assert.IsNotEmpty(mapping.PKs); - Assert.AreEqual("Id", mapping.PKs[0].Name); - Assert.IsTrue(mapping.PKs[0].IsPK); - Assert.IsFalse(mapping.PKs[0].IsAutoInc); + Assert.IsFalse(mapping.HasCompositePK); + Assert.IsNotNull(mapping.PK); + Assert.AreEqual("Id", mapping.PK.Name); + Assert.IsTrue(mapping.PK.IsPK); + Assert.IsFalse(mapping.PK.IsAutoInc); } [Test] @@ -162,7 +162,8 @@ public void WithoutImplicitMapping() TableMapping mapping = db.GetMapping(); - Assert.IsEmpty(mapping.PKs); + Assert.IsFalse(mapping.HasCompositePK); + Assert.IsNull(mapping.PK); TableMapping.Column column = mapping.Columns[2]; Assert.AreEqual("IndexedId", column.Name); diff --git a/tests/InheritanceTest.cs b/tests/InheritanceTest.cs index 8455bb1e7..6b9734084 100644 --- a/tests/InheritanceTest.cs +++ b/tests/InheritanceTest.cs @@ -28,7 +28,7 @@ public void InheritanceWorks() TableMapping mapping = db.GetMapping(); Assert.AreEqual(3, mapping.Columns.Length); - Assert.AreEqual("Id", mapping.PKs[0].Name); + Assert.AreEqual("Id", mapping.PK.Name); } } } \ No newline at end of file From b7a55714f4a8d30f8c54c0d86d9c9a307d59988f Mon Sep 17 00:00:00 2001 From: Igor Ralic Date: Sat, 11 Apr 2015 15:19:15 +0200 Subject: [PATCH 4/4] Cleanup and renaming PKs to CompositePK --- src/SQLite.Net/SQLiteConnection.cs | 72 +++++++++++++++--------------- src/SQLite.Net/TableMapping.cs | 18 ++++---- tests/DeleteTest.cs | 16 +++---- 3 files changed, 52 insertions(+), 54 deletions(-) diff --git a/src/SQLite.Net/SQLiteConnection.cs b/src/SQLite.Net/SQLiteConnection.cs index 86a64cfcb..952db75b3 100644 --- a/src/SQLite.Net/SQLiteConnection.cs +++ b/src/SQLite.Net/SQLiteConnection.cs @@ -378,12 +378,12 @@ public int CreateTable(Type ty, CreateFlags createFlags = CreateFlags.None) if (map.HasCompositePK) { - var PKs = mapColumns.Where(c => c.IsPK).ToList(); + var compositePK = mapColumns.Where(c => c.IsPK).ToList(); var decls = mapColumns.Select(p => Orm.SqlDecl(p, StoreDateTimeAsTicks, Serializer, ExtraTypeMappings, map.HasCompositePK)); var decl = string.Join(",\n", decls.ToArray()); query.Append(decl).Append(",\n"); - query.Append("primary key (").Append(string.Join(",", PKs.Select(pk => pk.Name))).Append(")"); + query.Append("primary key (").Append(string.Join(",", compositePK.Select(pk => pk.Name))).Append(")"); query.Append(")"); } else @@ -547,8 +547,6 @@ private void MigrateTable(TableMapping map) var toBeAdded = new List(); - var PKscount = map.Columns.Where(c => c.IsPK).Count(); - foreach (var p in map.Columns) { var found = false; @@ -825,17 +823,17 @@ public T Get(object pk) where T : class var map = GetMapping(typeof (T)); if (map.HasCompositePK) { - IDictionary PKs = pk as Dictionary; - if (PKs == null) + IDictionary compositePK = pk as Dictionary; + if (compositePK == null) { throw new NotSupportedException(map.TableName + " table has a composite primary key. Make sure primary key is passed in as Dictionary."); } - var pks = map.PKs; - if (PKs.Keys.Intersect(pks.Select(p => p.Name)).Count() < pks.Length) + var cpk = map.CompositePK; + if (compositePK.Keys.Intersect(cpk.Select(p => p.Name)).Count() < cpk.Length) { - throw new NotSupportedException("Cannot get from " + map.TableName + ": PKs mismatch. Make sure PK names are valid."); + throw new NotSupportedException("Cannot get from " + map.TableName + ": CompositePK mismatch. Make sure PK names are valid."); } - return Query(map.GetByPrimaryKeySql, PKs.Values.ToArray()).First(); + return Query(map.GetByPrimaryKeySql, compositePK.Values.ToArray()).First(); } else { @@ -878,17 +876,17 @@ public T Find(object pk) where T : class var map = GetMapping(typeof(T)); if (map.HasCompositePK) { - IDictionary PKs = pk as Dictionary; - if (PKs == null) + IDictionary compositePK = pk as Dictionary; + if (compositePK == null) { throw new NotSupportedException(map.TableName + " table has a composite primary key. Make sure primary key is passed in as Dictionary."); } - var pks = map.PKs; - if (PKs.Keys.Intersect(pks.Select(p => p.Name)).Count() < pks.Length) + var cpk = map.CompositePK; + if (compositePK.Keys.Intersect(cpk.Select(p => p.Name)).Count() < cpk.Length) { - throw new NotSupportedException("Cannot find in " + map.TableName + ": PKs mismatch. Make sure PK names are valid."); + throw new NotSupportedException("Cannot find in " + map.TableName + ": CompositePK mismatch. Make sure PK names are valid."); } - return Query(map.GetByPrimaryKeySql, PKs.Values.ToArray()).FirstOrDefault(); + return Query(map.GetByPrimaryKeySql, compositePK.Values.ToArray()).FirstOrDefault(); } else { @@ -936,17 +934,17 @@ public object Find(object pk, TableMapping map) { if (map.HasCompositePK) { - IDictionary PKs = pk as Dictionary; - if (PKs == null) + IDictionary compositePK = pk as Dictionary; + if (compositePK == null) { throw new NotSupportedException(map.TableName + " table has a composite primary key. Make sure primary key is passed in as Dictionary."); } - var pks = map.PKs; - if (PKs.Keys.Intersect(pks.Select(p => p.Name)).Count() < pks.Length) + var cpk = map.CompositePK; + if (compositePK.Keys.Intersect(cpk.Select(p => p.Name)).Count() < cpk.Length) { - throw new NotSupportedException("Cannot find in " + map.TableName + ": PKs mismatch. Make sure PK names are valid."); + throw new NotSupportedException("Cannot find in " + map.TableName + ": CompositePK mismatch. Make sure PK names are valid."); } - return Query(map, map.GetByPrimaryKeySql, PKs.Values.ToArray()).FirstOrDefault(); + return Query(map, map.GetByPrimaryKeySql, compositePK.Values.ToArray()).FirstOrDefault(); } else { @@ -1513,7 +1511,7 @@ public int Insert(object obj, string extra, Type objType) if (map.HasCompositePK) { - pk = map.PKs.FirstOrDefault(p => p.IsAutoGuid); + pk = map.CompositePK.FirstOrDefault(p => p.IsAutoGuid); } else { @@ -1635,19 +1633,19 @@ public int Update(object obj, Type objType) if (map.HasCompositePK) { - var pks = map.PKs; + var compositePK = map.CompositePK; var cols = from p in map.Columns - where !pks.Any(pk => pk == p) + where !compositePK.Any(pk => pk == p) select p; var pslist = (from c in cols select c.GetValue(obj)).ToList(); - pslist.AddRange(pks.Select(pk => pk.GetValue(obj))); + pslist.AddRange(compositePK.Select(pk => pk.GetValue(obj))); q = string.Format("update \"{0}\" set {1} where {2}", map.TableName, string.Join(",", (from c in cols - select "\"" + c.Name + "\" = ? ").ToArray()), string.Join(" and ", pks.Select(pk => "\"" + pk.Name + "\" = ? "))); + select "\"" + c.Name + "\" = ? ").ToArray()), string.Join(" and ", compositePK.Select(pk => "\"" + pk.Name + "\" = ? "))); ps = pslist.ToArray(); } @@ -1747,9 +1745,9 @@ public int Delete(object objectToDelete) if (map.HasCompositePK) { - var pks = map.PKs; - q = string.Format("delete from \"{0}\" where {1}", map.TableName, string.Join(" and ", pks.Select(pk => "\"" + pk.Name + "\" = ? "))); - ps = (from pk in pks + var compositePK = map.CompositePK; + q = string.Format("delete from \"{0}\" where {1}", map.TableName, string.Join(" and ", compositePK.Select(pk => "\"" + pk.Name + "\" = ? "))); + ps = (from pk in compositePK select pk.GetValue(objectToDelete)).ToArray(); } else @@ -1785,18 +1783,18 @@ public int Delete(object primaryKey) if (map.HasCompositePK) { - var pks = map.PKs; - IDictionary PKs = primaryKey as Dictionary; - if (PKs == null) + var cpk = map.CompositePK; + IDictionary compositePK = primaryKey as Dictionary; + if (compositePK == null) { throw new NotSupportedException(map.TableName + " table has a composite primary key. Make sure primary key is passed in as Dictionary."); } - if (PKs.Keys.Intersect(pks.Select(p => p.Name)).Count() < pks.Length) + if (compositePK.Keys.Intersect(cpk.Select(p => p.Name)).Count() < cpk.Length) { - throw new NotSupportedException("Cannot delete " + map.TableName + ": PKs mismatch. Make sure PK names are valid."); + throw new NotSupportedException("Cannot delete " + map.TableName + ": CompositePK mismatch. Make sure PK names are valid."); } - var q = string.Format("delete from \"{0}\" where {1}", map.TableName, string.Join(" and ", PKs.Keys.Select(pk => "\"" + pk + "\" = ? "))); - var ps = (from pk in PKs.Values + var q = string.Format("delete from \"{0}\" where {1}", map.TableName, string.Join(" and ", compositePK.Keys.Select(pk => "\"" + pk + "\" = ? "))); + var ps = (from pk in compositePK.Values select pk).ToArray(); return Execute(q, ps); } diff --git a/src/SQLite.Net/TableMapping.cs b/src/SQLite.Net/TableMapping.cs index 900e04b04..ba70b8e6e 100644 --- a/src/SQLite.Net/TableMapping.cs +++ b/src/SQLite.Net/TableMapping.cs @@ -58,9 +58,9 @@ public TableMapping(Type type, IEnumerable properties, CreateFlags } } Columns = cols.ToArray(); - PKs = Columns.Where(col => col.IsPK).ToArray(); + CompositePK = Columns.Where(col => col.IsPK).ToArray(); - if (PKs.Length > 1) + if (CompositePK.Length > 1) { HasCompositePK = true; } @@ -83,14 +83,14 @@ public TableMapping(Type type, IEnumerable properties, CreateFlags HasAutoIncPK = _autoPk != null; } - if (PKs.Length > 1) + if (CompositePK.Length > 1) { - string pksString = string.Join(" and ", PKs.Select(pk => "\"" + pk.Name + "\" = ? ")); - GetByPrimaryKeySql = string.Format("select * from \"{0}\" where {1}", TableName, pksString); + string compositePKString = string.Join(" and ", CompositePK.Select(pk => "\"" + pk.Name + "\" = ? ")); + GetByPrimaryKeySql = string.Format("select * from \"{0}\" where {1}", TableName, compositePKString); } - else if (PKs.Length == 1) + else if (PK != null) { - string pkString = PKs.FirstOrDefault().Name; + string pkString = PK.Name; GetByPrimaryKeySql = string.Format("select * from \"{0}\" where \"{1}\" = ?", TableName, pkString); } else @@ -116,7 +116,7 @@ public Column PK { if (HasCompositePK) { - throw new NotSupportedException("Table has a composite primary key. Use PKs property instead."); + throw new NotSupportedException("Table has a composite primary key. Use CompositePK property instead."); } else { @@ -126,7 +126,7 @@ public Column PK } [PublicAPI] - public Column[] PKs { get; private set; } + public Column[] CompositePK { get; private set; } [PublicAPI] public string GetByPrimaryKeySql { get; private set; } diff --git a/tests/DeleteTest.cs b/tests/DeleteTest.cs index 11d48a094..6de95a320 100644 --- a/tests/DeleteTest.cs +++ b/tests/DeleteTest.cs @@ -164,11 +164,11 @@ public void DeletePKNoneComposite() { var db = CreateDb(); - var pks = new Dictionary(); - pks.Add("Id", 348597); - pks.Add("TestIndex", 348598); + var compositePK = new Dictionary(); + compositePK.Add("Id", 348597); + compositePK.Add("TestIndex", 348598); - var r = db.Delete(pks); + var r = db.Delete(compositePK); Assert.AreEqual(0, r); Assert.AreEqual(Count, db.Table().Count()); @@ -179,11 +179,11 @@ public void DeletePKOneComposite() { var db = CreateDb(); - var pks = new Dictionary(); - pks.Add("Id", 1); - pks.Add("TestIndex", 2); + var compositePK = new Dictionary(); + compositePK.Add("Id", 1); + compositePK.Add("TestIndex", 2); - var r = db.Delete(pks); + var r = db.Delete(compositePK); Assert.AreEqual(1, r); Assert.AreEqual(Count - 1, db.Table().Count());