InsertOrReplaceAllWithChildren crashes when child list object is empty instead null

Issue #113 new
Emil Alipiev created an issue

I am having an web api which returns list of objects with sub objects. for example

- List<ObjectMain>-> List<ObjectImage> ObjectImages
                             ->List<ObjectComment> ObjectComments

In my api I am returning Objects with sub objects included. By default if Object doesnt have ObjectImages, regardless list is empty or null, it will throw exception

 public IQueryable<Object> GetObjectsWithChildren()
        { 
            return db.Objects
                .Include(e => e.ObjectImages)
                .Include(e => e.ObjectComments);               
        }

So in my viewmodel I make a call to api to get Objects with children as below. Objects are returned but some objects dont have objectImage mapping

                var Items = await Api.GetObjectsWithChildren();
                if (Items?.Count > 0)
                {
                     await db_async.InsertOrReplaceAllWithChildrenAsync(Items);
                }

Problem is I have a property which is defined as NotNull(ImageId) in this object, since Object is returned as empty list or null, it will complain about this object with the exception below. Why is attempting to insert if object is null or empty

    public  class ObjectImage 
    {
        [PrimaryKey, AutoIncrement, Unique, NotNull]
        public int id { get; set; }

        [ForeignKey(typeof(Database.Model.Image)), NotNull]
        public int ImageId { get; set; }
  SQLite.Net.NotNullConstraintViolationExceptionNOT NULL constraint failed: ObjectImage.ImageId
Raw
  at SQLite.Net.SQLiteCommand.ExecuteNonQuery () [0x000c7] in <00cd4299895343388a532f755967caf0>:0 
  at SQLite.Net.SQLiteConnection.Execute (System.String query, System.Object[] args) [0x00044] in <00cd4299895343388a532f755967caf0>:0 
  at SQLiteNetExtensions.Extensions.WriteOperations.UpdateOneToManyInverseForeignKey (SQLite.Net.SQLiteConnection conn, System.Object element, System.Reflection.PropertyInfo relationshipProperty) [0x00200] in /Users/redent/Documents/workspace/sqlite-net-extensions/SQLiteNetExtensions/Extensions/WriteOperations.cs:461 
  at SQLiteNetExtensions.Extensions.WriteOperations.UpdateInverseForeignKeys (SQLite.Net.SQLiteConnection conn, System.Object element) [0x00040] in /Users/redent/Documents/workspace/sqlite-net-extensions/SQLiteNetExtensions/Extensions/WriteOperations.cs:394 
  at SQLiteNetExtensions.Extensions.WriteOperations.UpdateWithChildren (SQLite.Net.SQLiteConnection conn, System.Object element) [0x0000e] in /Users/redent/Documents/workspace/sqlite-net-extensions/SQLiteNetExtensions/Extensions/WriteOperations.cs:51 
  at SQLiteNetExtensions.Extensions.WriteOperations.InsertAllWithChildrenRecursive (SQLite.Net.SQLiteConnection conn, System.Collections.IEnumerable elements, System.Boolean replace, System.Boolean recursive, System.Collections.Generic.ISet`1[T] objectCache) [0x0007f] in /Users/redent/Documents/workspace/sqlite-net-extensions/SQLiteNetExtensions/Extensions/WriteOperations.cs:177 
  at SQLiteNetExtensions.Extensions.WriteOperations.InsertOrReplaceAllWithChildren (SQLite.Net.SQLiteConnection conn, System.Collections.IEnumerable elements, System.Boolean recursive) [0x00000] in /Users/redent/Documents/workspace/sqlite-net-extensions/SQLiteNetExtensions/Extensions/WriteOperations.cs:115 
  at SQLiteNetExtensionsAsync.Extensions.WriteOperations+<InsertOrReplaceAllWithChildrenAsync>c__async4+<InsertOrReplaceAllWithChildrenAsync>c__AnonStoreyC.<>m__0 () [0x00013] in /Users/redent/Documents/workspace/sqlite-net-extensions/SQLiteNetExtensionsAsync-PCL/Extensions/WriteOperations.cs:143 
  at System.Threading.Tasks.Task.InnerInvoke () [0x00012] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs:2879 
  at System.Threading.Tasks.Task.Execute () [0x00016] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs:2502 
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:143 
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x00047] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:187 
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x0002e] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:156 
  at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x0000b] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:128 
  at System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult () [0x00000] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:447 
  at SQLiteNetExtensionsAsync.Extensions.WriteOperations+<InsertOrReplaceAllWithChildrenAsync>c__async4.MoveNext () [0x0005f] in /Users/redent/Documents/workspace/sqlite-net-extensions/SQLiteNetExtensionsAsync-PCL/Extensions/WriteOperations.cs:138 
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:143 
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x00047] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:187 
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x0002e] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:156 
  at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x0000b] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:128 
  at System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:113     

Comments (4)

  1. Guillermo GutiƩrrez

    The error looks self-explanatory. You have a not nullable foreign key property that it's being set to null because the object it references is also null. If this case should be supported, remove the NotNull property from the ForeignKey property. Otherwise check why your relationship property (not included in your sample code) is null when the object is being inserted.

  2. Emil Alipiev reporter

    You say in your other post. it is not good practice to use InsertOrReplaceAllWithChildren when there are OneToMany or ManyToOne relationships. Is it better to use InsertAllWithChildren instead? if yes, does it handle updates as well if there are existing rows and childen?

  3. Guillermo GutiƩrrez

    Calling InsertOrReplaceWithChildren will call InsertOrReplace instead of Insert when inserting objects to database. It doesn't add any additional handling. It's hard to tell which one is better for you, because they do different things.

  4. Log in to comment