Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multiple primary keys in schema. Fixes #280 #281

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 83 additions & 51 deletions src/SQLite.cs
Original file line number Diff line number Diff line change
Expand Up @@ -364,10 +364,17 @@ public int CreateTable(Type ty, CreateFlags createFlags = CreateFlags.None)
_tables.Add (ty.FullName, map);
}
var query = "create table if not exists \"" + map.TableName + "\"(\n";

var decls = map.Columns.Select (p => Orm.SqlDecl (p, StoreDateTimeAsTicks));

var pkCols = map.Columns.Where(p => p.IsPK);
int numPkCols = pkCols.Count();

var decls = map.Columns.Select(p => Orm.SqlDecl(p, StoreDateTimeAsTicks, numPkCols == 1));
var decl = string.Join (",\n", decls.ToArray ());
query += decl;

if (numPkCols > 1)
query += string.Format(",\nprimary key ({0})\n", string.Join(", ", pkCols.Select(p => "\"" + p.Name + "\"")));

query += ")";

var count = Execute (query);
Expand Down Expand Up @@ -1234,35 +1241,39 @@ public int Insert (object obj, string extra, Type objType)
var map = GetMapping (objType);

#if NETFX_CORE
if (map.PK != null && map.PK.IsAutoGuid)
{
// no GetProperty so search our way up the inheritance chain till we find it
PropertyInfo prop;
while (objType != null)
{
var info = objType.GetTypeInfo();
prop = info.GetDeclaredProperty(map.PK.PropertyName);
if (prop != null)
{
if (prop.GetValue(obj, null).Equals(Guid.Empty))
{
prop.SetValue(obj, Guid.NewGuid(), null);
}
break;
}

objType = info.BaseType;
}
}
foreach (var pk in map.PKs)
{
if (pk.IsAutoGuid)
{
// no GetProperty so search our way up the inheritance chain till we find it
PropertyInfo prop;
while (objType != null)
{
var info = objType.GetTypeInfo();
prop = info.GetDeclaredProperty(pk.PropertyName);
if (prop != null)
{
if (prop.GetValue(obj, null).Equals(Guid.Empty))
{
prop.SetValue(obj, Guid.NewGuid(), null);
}
break;
}
objType = info.BaseType;
}
}
}
#else
if (map.PK != null && map.PK.IsAutoGuid) {
var prop = objType.GetProperty(map.PK.PropertyName);
if (prop != null) {
if (prop.GetValue(obj, null).Equals(Guid.Empty)) {
prop.SetValue(obj, Guid.NewGuid(), null);
}
}
}
foreach (var pk in map.PKs) {
if (pk.IsAutoGuid) {
var prop = objType.GetProperty(pk.PropertyName);
if (prop != null) {
if (prop.GetValue(obj, null).Equals(Guid.Empty)) {
prop.SetValue(obj, Guid.NewGuid(), null);
}
}
}
}
#endif


Expand Down Expand Up @@ -1342,21 +1353,22 @@ public int Update (object obj, Type objType)

var map = GetMapping (objType);

var pk = map.PK;

if (pk == null) {
var pks = map.PKs;
if (pks.Count == 0) {
throw new NotSupportedException ("Cannot update " + map.TableName + ": it has no PK");
}

var cols = from p in map.Columns
where p != pk
where !p.IsPK
select p;
var vals = from c in cols
select c.GetValue (obj);
var ps = new List<object> (vals);
ps.Add (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);

var q = string.Format ("update \"{0}\" set {1} {2} ", map.TableName, string.Join (",", (from c in cols
select "\"" + c.Name + "\" = ? ").ToArray ()), map.GetPrimaryKeyClause());

var ps = new List<object>(vals);
ps.AddRange(pks.Select(pk => pk.GetValue(obj)));

try {
rowsAffected = Execute (q, ps.ToArray ());
Expand Down Expand Up @@ -1408,12 +1420,12 @@ public int UpdateAll (System.Collections.IEnumerable objects)
public int Delete (object objectToDelete)
{
var map = GetMapping (objectToDelete.GetType ());
var pk = map.PK;
if (pk == null) {
var pks = map.PKs;
if (pks.Count == 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);
var count = Execute (q, pk.GetValue (objectToDelete));
var q = string.Format ("delete from \"{0}\" {1}", map.TableName, map.GetPrimaryKeyClause());
var count = Execute (q, pks.Select(pk => pk.GetValue (objectToDelete)).ToArray());
if (count > 0)
OnTableChanged (map, NotifyTableChangedAction.Delete);
return count;
Expand All @@ -1434,11 +1446,14 @@ public int Delete (object objectToDelete)
public int Delete<T> (object primaryKey)
{
var map = GetMapping (typeof (T));
var pk = map.PK;
if (pk == null) {
var pks = map.PKs;
if (pks.Count == 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);
if (pks.Count > 1) {
throw new NotSupportedException("Cannot delete " + map.TableName + ": it has > 1 PK");
}
var q = string.Format ("delete from \"{0}\" {1}", map.TableName, map.GetPrimaryKeyClause());
var count = Execute (q, primaryKey);
if (count > 0)
OnTableChanged (map, NotifyTableChangedAction.Delete);
Expand Down Expand Up @@ -1658,7 +1673,7 @@ public class TableMapping

public Column[] Columns { get; private set; }

public Column PK { get; private set; }
public List<Column> PKs { get; private set; }

public string GetByPrimaryKeySql { get; private set; }

Expand Down Expand Up @@ -1698,26 +1713,43 @@ public TableMapping(Type type, CreateFlags createFlags = CreateFlags.None)
}
}
Columns = cols.ToArray ();
PKs = new List<Column>();
foreach (var c in Columns) {
if (c.IsAutoInc && c.IsPK) {
_autoPk = c;
}
if (c.IsPK) {
PK = c;
PKs.Add(c);
}
}

HasAutoIncPK = _autoPk != null;

if (PK != null) {
GetByPrimaryKeySql = string.Format ("select * from \"{0}\" where \"{1}\" = ?", TableName, PK.Name);
if (PKs.Count > 0) {
GetByPrimaryKeySql = string.Format("select * from \"{0}\" {1}", TableName, GetPrimaryKeyClause()); ;
}
else {
// People should not be calling Get/Find without a PK
GetByPrimaryKeySql = string.Format ("select * from \"{0}\" limit 1", TableName);
}
}

public string GetPrimaryKeyClause()
{
string clause = String.Empty;
bool first = true;
foreach (Column pk in PKs) {
if (first) {
clause += "where ";
first = false;
} else {
clause += " and ";
}
clause += string.Format("\"{0}\" = ?", pk.Name);
}
return clause;
}

public bool HasAutoIncPK { get; private set; }

public void SetAutoIncPK (object obj, long id)
Expand Down Expand Up @@ -1883,11 +1915,11 @@ public static class Orm
public const string ImplicitPkName = "Id";
public const string ImplicitIndexSuffix = "Id";

public static string SqlDecl (TableMapping.Column p, bool storeDateTimeAsTicks)
public static string SqlDecl (TableMapping.Column p, bool storeDateTimeAsTicks, bool trySetAsPrimaryKey = true)
{
string decl = "\"" + p.Name + "\" " + SqlType (p, storeDateTimeAsTicks) + " ";

if (p.IsPK) {
if (trySetAsPrimaryKey && p.IsPK) {
decl += "primary key ";
}
if (p.IsAutoInc) {
Expand Down
6 changes: 4 additions & 2 deletions src/SQLiteAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -410,8 +410,10 @@ public Entry (SQLiteConnectionString connectionString, SQLiteOpenFlags openFlags

public void OnApplicationSuspended ()
{
Connection.Dispose ();
Connection = null;
if (Connection != null) {
Connection.Dispose ();
Connection = null;
}
}
}

Expand Down
56 changes: 31 additions & 25 deletions tests/CreateTableImplicitTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public void WithoutImplicitMapping ()

var mapping = db.GetMapping<NoAttributes>();

Assert.IsNull (mapping.PK);
Assert.AreEqual(mapping.PKs.Count, 0);

var column = mapping.Columns[2];
Assert.AreEqual("IndexedId", column.Name);
Expand All @@ -72,10 +72,11 @@ public void ImplicitPK()

var mapping = db.GetMapping<NoAttributes>();

Assert.IsNotNull(mapping.PK);
Assert.AreEqual("Id", mapping.PK.Name);
Assert.IsTrue(mapping.PK.IsPK);
Assert.IsFalse(mapping.PK.IsAutoInc);
Assert.AreNotEqual(mapping.PKs.Count, 0);
var pk = mapping.PKs.First();
Assert.AreEqual("Id", pk.Name);
Assert.IsTrue(pk.IsPK);
Assert.IsFalse(pk.IsAutoInc);

CheckPK(db);
}
Expand All @@ -90,10 +91,11 @@ public void ImplicitAutoInc()

var mapping = db.GetMapping<PkAttribute>();

Assert.IsNotNull(mapping.PK);
Assert.AreEqual("Id", mapping.PK.Name);
Assert.IsTrue(mapping.PK.IsPK);
Assert.IsTrue(mapping.PK.IsAutoInc);
Assert.AreNotEqual(mapping.PKs.Count, 0);
var pk = mapping.PKs.First();
Assert.AreEqual("Id", pk.Name);
Assert.IsTrue(pk.IsPK);
Assert.IsTrue(pk.IsAutoInc);
}

[Test]
Expand All @@ -118,10 +120,11 @@ public void ImplicitPKAutoInc()

var mapping = db.GetMapping<NoAttributes>();

Assert.IsNotNull(mapping.PK);
Assert.AreEqual("Id", mapping.PK.Name);
Assert.IsTrue(mapping.PK.IsPK);
Assert.IsTrue(mapping.PK.IsAutoInc);
Assert.AreNotEqual(mapping.PKs.Count, 0);
var pk = mapping.PKs.First();
Assert.AreEqual("Id", pk.Name);
Assert.IsTrue(pk.IsPK);
Assert.IsTrue(pk.IsAutoInc);
}

[Test]
Expand All @@ -133,10 +136,11 @@ public void ImplicitAutoIncAsPassedInTypes()

var mapping = db.GetMapping<PkAttribute>();

Assert.IsNotNull(mapping.PK);
Assert.AreEqual("Id", mapping.PK.Name);
Assert.IsTrue(mapping.PK.IsPK);
Assert.IsTrue(mapping.PK.IsAutoInc);
Assert.AreNotEqual(mapping.PKs.Count, 0);
var pk = mapping.PKs.First();
Assert.AreEqual("Id", pk.Name);
Assert.IsTrue(pk.IsPK);
Assert.IsTrue(pk.IsAutoInc);
}

[Test]
Expand All @@ -148,10 +152,11 @@ public void ImplicitPkAsPassedInTypes()

var mapping = db.GetMapping<NoAttributes>();

Assert.IsNotNull(mapping.PK);
Assert.AreEqual("Id", mapping.PK.Name);
Assert.IsTrue(mapping.PK.IsPK);
Assert.IsFalse(mapping.PK.IsAutoInc);
Assert.AreNotEqual(mapping.PKs.Count, 0);
var pk = mapping.PKs.First();
Assert.AreEqual("Id", pk.Name);
Assert.IsTrue(pk.IsPK);
Assert.IsFalse(pk.IsAutoInc);
}

[Test]
Expand All @@ -163,10 +168,11 @@ public void ImplicitPKAutoIncAsPassedInTypes()

var mapping = db.GetMapping<NoAttributes>();

Assert.IsNotNull(mapping.PK);
Assert.AreEqual("Id", mapping.PK.Name);
Assert.IsTrue(mapping.PK.IsPK);
Assert.IsTrue(mapping.PK.IsAutoInc);
Assert.AreNotEqual(mapping.PKs.Count, 0);
var pk = mapping.PKs.First();
Assert.AreEqual("Id", pk.Name);
Assert.IsTrue(pk.IsPK);
Assert.IsTrue(pk.IsAutoInc);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/InheritanceTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public void InheritanceWorks ()
var mapping = db.GetMapping<Derived> ();

Assert.AreEqual (3, mapping.Columns.Length);
Assert.AreEqual ("Id", mapping.PK.Name);
Assert.AreEqual ("Id", mapping.PKs.First().Name);
}
}
}
Loading