Search code examples
c#sqlitexamarin.formsxamarin.iosjit

Xamarin.Forms SQLite code first add element to an foreign element with list of the given element


I currently create a project with Xamarin.Forms and SQLite. Therefore I use CodeFirst for my database creation.

My database works without problems when creating or adding primitive elements or edit existing ones.

But even it works here my database model:

private string _path = string.Empty;
public MyDatabaseContext()
{
     _path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "..", "Library", "Monitoring_Tool_LocalDb.db");
     this.Database.EnsureCreated();
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseSqlite($"Filename={_path}");
}

Including the following sets for example

public DbSet<MyMainObject> MyMainObjects { get; set; }
public DbSet<MySubObject> MySubObjects { get; set; }

The classes:

// This class includs all base elements and is only there to get the 
// minimum required attributes (could also be defined as abstract)
public class BaseClassElement 
{
    public Int64 Id { get; set; }
    public Guid SomeGuidElement { get; set; }
    public DateTime LastChange { get; set; }
}

public class MyMainObject : BaseClassElement
{
   public string Designation { get; set; }
   public virtual ICollection<MySubObject> MySubObjects { get; set; }
}

public class MySubObject: BaseClassElement
{
   public string Designation { get; set; }
   public virtual MyMainObject MyMainObject { get; set; }
}

Now to my problem:

If I now add a main object to the database like:

db.MyMainObjects.Add(myObjectWithNewData);
db.SaveChanges();

Everything went well. The object was added and I also used DateTime.Now to set the last change. Also I set the Guid to Guid.Empty.

Now if I try to do this: (I know, I could write less but I tried every method in every order to prevent that some error is happening there but nothing worked...)

// Element loaded from database without problems
var dbMainObject = db.MyMainObjects.Include("MySubObjects").SingleOrDefault(s => s.Id == myParameterGivenId);
var newlyGeneratedSubObject = new MySubObject() 
{
   MyMainObject = dbMainObject,
   ... // Other data set
};
db.MySubObjects.Add(newlyGeneratedSubObject);
dbMainObject.MySubObjects.Add(newlyGeneratedSubObject);
db.SaveChanges();

The method will throw the following exception:

Attempting to JIT compile method '(wrapper runtime-invoke) :runtime_invoke_void_this__long_byte_object_DateTime_object_object_Guid_object_int (object,intptr,intptr,intptr)' while running in aot-only mode.

This error is also referencing to the following page like this:

See https://developer.xamarin.com/guides/ios/advanced_topics/limitations/

I use the following nuget packages:

Microsoft.EntityFrameworkCore.Sqlite (2.0.1)

Xamarin.Forms (2.5.0.122203)

WinInsider.System.Net.Http.Formatting (1.0.5)

Newtonsoft.Json (10.0.3)

NETStandard.Library (2.0.1)

This is what I tried so far

Method OnConfiguring added: optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);

(therfore I used manually tracking)

db.Entry<MyElement>(myObjectFromElement).State = EntityState.Added;

Also db.Database.ExecuteSqlCommand("INSERT ...")

And db.Set<MyElement>().Add(myObjectFromElement)

Edit 1:

Need to mention: This error is only caused on the real runtime device. I tested it with an iPhone X Latest version and an iPad (Don't know which generation exactly but it's also on the latest version 12.2.5)

In the simulator everything went well.

Edit 2:

Changed context name

Edit 3:

Well, I finally got my stack trace. (Error hasn't changed, I just have more detailed informations)

System.Reflection.MonoCMethod:InternalInvoke (System.Reflection.MonoCMethod,object,object[],System.Exception&)

at System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) <0x100b2b000 + 0x0002f> in :0

--- End of stack trace from previous location where exception was thrown ---

at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () <0x100ca6040 + 0x00028> in :0

at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw (System.Exception source) <0x100ca6080 + 0x00023> in :0

at System.Linq.Expressions.Interpreter.ExceptionHelpers.UnwrapAndRethrow (System.Reflection.TargetInvocationException exception) <0x1026e2fe0 + 0x0001b> in <98d8ae0ba2c1456c96653359c4b1be27#c1614e788b2679307c28b34eca2b14d3>:0

at System.Linq.Expressions.Interpreter.NewInstruction.Run (System.Linq.Expressions.Interpreter.InterpretedFrame frame) <0x1026de640 + 0x0005f> in <98d8ae0ba2c1456c96653359c4b1be27#c1614e788b2679307c28b34eca2b14d3>:0

at System.Linq.Expressions.Interpreter.Interpreter.Run (System.Linq.Expressions.Interpreter.InterpretedFrame frame) <0x1026c5cd0 + 0x00087> in <98d8ae0ba2c1456c96653359c4b1be27#c1614e788b2679307c28b34eca2b14d3>:0

at System.Linq.Expressions.Interpreter.LightLambda.Run1[T0,TRet] (T0 arg0) <0x1026d5570 + 0x00073> in <98d8ae0ba2c1456c96653359c4b1be27#c1614e788b2679307c28b34eca2b14d3>:0

at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry+OriginalValues..ctor (Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry entry) <0x10360db50 + 0x0003f> in :0

at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.EnsureOriginalValues () <0x1035abd50 + 0x0003b> in :0

at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntrySubscriber.SnapshotAndSubscribe (Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry entry) <0x1035afc30 + 0x00053> in :0

at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTracking (Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry entry) <0x1035d1cb0 + 0x001fb> in :0

at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState (Microsoft.EntityFrameworkCore.EntityState oldState, Microsoft.EntityFrameworkCore.EntityState newState, System.Boolean acceptChanges) <0x1035a9ce0 + 0x00537> in :0

at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState (Microsoft.EntityFrameworkCore.EntityState entityState, System.Boolean acceptChanges, System.Boolean forceStateWhenUnknownKey) <0x1035a9740 + 0x000fb> in :0

at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.PaintAction (Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntryGraphNode node) <0x1035a6e20 + 0x00113> in :0

at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph (Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntryGraphNode node, System.Func`2[T,TResult] handleNode) <0x1035a6480 + 0x00047> in :0

at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.AttachGraph (Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry rootEntry, Microsoft.EntityFrameworkCore.EntityState entityState, System.Boolean forceStateWhenUnknownKey) <0x1035a6b00 + 0x0018b> in :0

at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.NavigationCollectionChanged (Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry entry, Microsoft.EntityFrameworkCore.Metadata.INavigation navigation, System.Collections.Generic.IEnumerable1[T] added, System.Collections.Generic.IEnumerable1[T] removed) <0x1035b2fd0 + 0x0041f> in :0

at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntryNotifier.NavigationCollectionChanged (Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry entry, Microsoft.EntityFrameworkCore.Metadata.INavigation navigation, System.Collections.Generic.IEnumerable1[T] added, System.Collections.Generic.IEnumerable1[T] removed) <0x1035af910 + 0x00093> in :0

at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ChangeDetector.DetectNavigationChange (Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry entry, Microsoft.EntityFrameworkCore.Metadata.INavigation navigation) <0x1035a31b0 + 0x00573> in :0

at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ChangeDetector.DetectChanges (Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry entry) <0x1035a2c80 + 0x00343> in :0

at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ChangeDetector.DetectChanges (Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IStateManager stateManager) <0x1035a2a10 + 0x001ff> in :0

at Microsoft.EntityFrameworkCore.ChangeTracking.ChangeTracker.DetectChanges () <0x103598dd0 + 0x0004b> in :0

at Microsoft.EntityFrameworkCore.DbContext.TryDetectChanges () <0x1034b39f0 + 0x0005f> in :0

at Microsoft.EntityFrameworkCore.DbContext.SaveChanges (System.Boolean acceptAllChangesOnSuccess) <0x1034b38f0 + 0x00027> in :0

at Microsoft.EntityFrameworkCore.DbContext.SaveChanges () <0x1034b38b0 + 0x00023> in :0

at MobileClient.Communicator.MyCommunicator.Add (Client.Businesslogic.ViewModels.MyElementViewModel myElement, System.Int64 roomTypeId) <0x102fc0250 + 0x0063b> in <1fe0ef9dc3fa4068840d6bf326c56b38#c1614e788b2679307c28b34eca2b14d3>:0

at Mobile.MobileClient.Skins.MySkins.AddElementUserControl.AddElementSave (System.Object sender, System.Object e) <0x102f61090 + 0x000ff> in <1fe0ef9dc3fa4068840d6bf326c56b38#c1614e788b2679307c28b34eca2b14d3>:0


Solution

  • This error is caused by a limitation on the size of arguments that can be passed to a dynamic call in Xamarin.iOS. The current plan is for the fix to be included in the 15.7 release (i.e. Xamarin.iOS 11.9).

    See https://bugzilla.xamarin.com/show_bug.cgi?id=59184 for more details on the Xamarin.iOS issue.

    There is also some information and workarounds customers have tried on the corresponding tracking issue for EF Core at https://github.com/aspnet/EntityFrameworkCore/issues/9249.