2013-08-14 2 views
3

Я пытаюсь удалить записи для типа, который я храню в своей базе данных Sqlite. Это неудачу со следующим сообщением:База данных Sqlite не может удалять объекты, не удается с сообщением «Не удается сохранить тип: <type>»

"Cannot store type: MyNamespace.PanelLog" 

я следующий метод для удаления записей:

public static int DeletePanelLog(int id) 
    { 
     return me.db.DeleteItem<PanelLog>(id); 
    } 

где DeleteItem определяется как:

public int DeleteItem<T>(int id) where T : IBusinessEntity, new() 
    { 
     lock (locker) { 
#if NETFX_CORE 
      return Delete(new T() { ID = id }); 
#else 
      return Delete<T> (new T() { ID = id }); 
#endif 
     } 
    } 

PanelLog определяется как:

public class PanelLog : IBusinessEntity 
{ 
    public PanelLog(){} 

    [PrimaryKey, AutoIncrement] 
    public int ID { get; set; } 

    public uint Sequence { get; set; } 
    public DateTime Time { get; set; } 
    public string Message { get; set; } 
    public bool Alarm { get; set; } 
} 

Ниже приведен стека вызовов из SQLite:

public int Delete<T>(object primaryKey) 
    { 
     var map = GetMapping(typeof(T)); 
     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); // in this case, primaryKey is a PanelLog object 
    } 

    public int Execute(string query, params object[] args) 
    { 
     var cmd = CreateCommand(query, args); 

     if (TimeExecution) 
     { 
      if (_sw == null) 
      { 
       _sw = new Stopwatch(); 
      } 
      _sw.Reset(); 
      _sw.Start(); 
     } 

     var r = cmd.ExecuteNonQuery(); 

     if (TimeExecution) 
     { 
      _sw.Stop(); 
      _elapsedMilliseconds += _sw.ElapsedMilliseconds; 
      Debug.WriteLine(string.Format("Finished in {0} ms ({1:0.0} s total)", _sw.ElapsedMilliseconds, _elapsedMilliseconds/1000.0)); 
     } 

     return r; 
    } 

    public int ExecuteNonQuery() 
    { 
     if (_conn.Trace) 
     { 
      Debug.WriteLine("Executing: " + this); 
     } 

     var r = SQLite3.Result.OK; 
     var stmt = Prepare(); 
     r = SQLite3.Step(stmt); 
     Finalize(stmt); 
     if (r == SQLite3.Result.Done) 
     { 
      int rowsAffected = SQLite3.Changes(_conn.Handle); 
      return rowsAffected; 
     } 
     else if (r == SQLite3.Result.Error) 
     { 
      string msg = SQLite3.GetErrmsg(_conn.Handle); 
      throw SQLiteException.New(r, msg); 
     } 
     else 
     { 
      throw SQLiteException.New(r, r.ToString()); 
     } 
    } 

    Sqlite3Statement Prepare() 
    { 
     var stmt = SQLite3.Prepare2(_conn.Handle, CommandText); 
     BindAll(stmt); 
     return stmt; 
    } 

    void BindAll(Sqlite3Statement stmt) 
    { 
     int nextIdx = 1; 
     foreach (var b in _bindings) 
     { 
      if (b.Name != null) 
      { 
       b.Index = SQLite3.BindParameterIndex(stmt, b.Name); 
      } 
      else 
      { 
       b.Index = nextIdx++; 
      } 

      BindParameter(stmt, b.Index, b.Value, _conn.StoreDateTimeAsTicks); 
     } 
    } 

Выполнение терпит неудачу в последней строке следующее: (line 1051 here)

// line 1027 of http://code.google.com/p/sqlite-net/source/browse/trunk/src/SQLite.cs 
internal static void BindParameter(Sqlite3Statement stmt, int index, object value, bool storeDateTimeAsTicks) 
{ 
    if (value == null) 
    { 
     SQLite3.BindNull(stmt, index); 
    } 
    else 
    { 
     if (value is Int32) 
     { 
      SQLite3.BindInt(stmt, index, (int)value); 
     } 
     else if (value is String) 
     { 
      SQLite3.BindText(stmt, index, (string)value, -1, NegativePointer); 
     } 
     else if (value is Byte || value is UInt16 || value is SByte || value is Int16) 
     { 
      SQLite3.BindInt(stmt, index, Convert.ToInt32(value)); 
     } 
     else if (value is Boolean) 
     { 
      SQLite3.BindInt(stmt, index, (bool)value ? 1 : 0); 
     } 
     else if (value is UInt32 || value is Int64) 
     { 
      SQLite3.BindInt64(stmt, index, Convert.ToInt64(value)); 
     } 
     else if (value is Single || value is Double || value is Decimal) 
     { 
      SQLite3.BindDouble(stmt, index, Convert.ToDouble(value)); 
     } 
     else if (value is DateTime) 
     { 
      if (storeDateTimeAsTicks) 
      { 
       SQLite3.BindInt64(stmt, index, ((DateTime)value).Ticks); 
      } 
      else 
      { 
       SQLite3.BindText(stmt, index, ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss"), -1, NegativePointer); 
      } 
#if !NETFX_CORE 
     } 
     else if (value.GetType().IsEnum) 
     { 
#else 
} else if (value.GetType().GetTypeInfo().IsEnum) { 
#endif 
      SQLite3.BindInt(stmt, index, Convert.ToInt32(value)); 
     } 
     else if (value is byte[]) 
     { 
      SQLite3.BindBlob(stmt, index, (byte[])value, ((byte[])value).Length, NegativePointer); 
     } 
     else if (value is Guid) 
     { 
      SQLite3.BindText(stmt, index, ((Guid)value).ToString(), 72, NegativePointer); 
     } 
     else 
     { 
      throw new NotSupportedException("Cannot store type: " + value.GetType()); 
     } 
    } 
} 

Это, кажется, пытается связать тип объекта, а чем значение объекта. Это верно? Есть ли что-нибудь, что я могу сделать, чтобы исправить это?

EDIT:

После некоторого дальнейшего тестирования, кажется, следующие работы:

public int Delete(object objectToDelete) 
    { 
     var map = GetMapping(objectToDelete.GetType()); 
     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, pk.GetValue(objectToDelete)); 
    } 

ответ

3

Вместо использования:

public int DeleteItem<T>(int id) where T : IBusinessEntity, new() 
    { 
     lock (locker) { 
    #if NETFX_CORE 
      return Delete(new T() { ID = id }); 
    #else 
      return Delete<T> (new T() { ID = id }); 
    #endif 
     } 
    } 

Используйте вместо этого:

public int Delete(object objectToDelete) 
    { 
     var map = GetMapping(objectToDelete.GetType()); 
     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, pk.GetValue(objectToDelete)); 
    } 
+0

Удобное решение! Большое спасибо. Я получил этот ORM из [здесь] (https://github.com/xamarinDevs/Tasky/commits/master/Android_PaidEdition/Tasky.Core/SQLite.cs) - возможно, вы можете добавить тег или два к своему вопросу, чтобы помочь людям найти это проще. Возможно, «Хамарин»? –

8

Я также столкнулся с этой проблемой. На самом деле это происходит от линии внутри определения DeleteItem:

return Delete<T> (new T() { ID = id }); 

Оно должно быть:

return Delete<T> (id); 
+0

Означает ли это, что код SQLite неверен? – DaveDev

+0

Это не код SQLite. Это из некоторых (xamarin?) Образцов. Как и этот: https://github.com/xamarin/mobile-samples/blob/master/TaskyPro/Tasky.Core/DataLayer/TaskDatabase.cs – Jfly

+0

Это должен быть правильный ответ, спасибо человеку. Это вторая, полученная мной из примера Tasky Pro, мне придется взять предоставленные примеры с солью, идущей вперед –