0

I've got a problem using EntityFrameworkCore with SQLite on a physical device. It works without any issue on the iPhone xR simulator, but not on the iPhone 6 simulator, or on a physical device. But it works fine on Android as far as I can tell.

The problem is that when the EnsureCreatedAsync() method is called, the app crashes (it doesn't even unwind to the catch I've got wrapped around it), with the following error:

enter image description here

In the screenshot this method is called in the constructor of the context, although I have tried moving it to an async method and awaiting it and the same issue occurs. This is the code for my context:

public class Database : DbContext
    {
        public Database()
        {
            try
            {
                Database.EnsureCreatedAsync();
            }
            catch (Exception ex)
            {
                Debug.Write(ex.Message);
            }
        }

        public DbSet<TextRecordModel> TextRecords { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            base.OnConfiguring(optionsBuilder);

            String databasePath = "";
            switch (Device.RuntimePlatform)
            {
                case Device.iOS:
                    SQLitePCL.Batteries_V2.Init();
                    databasePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "..", "Library", "TestDB.db");
                    break;
                case Device.Android:
                    databasePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "TestDB.db");
                    break;
                default:
                    throw new NotImplementedException("Platform not supported");
            }

            optionsBuilder.UseSqlite($"Filename={databasePath}");

        }        

        public async Task<bool> SaveTextRecordAsync(TextRecordModel record)
        {
            try
            {
                await TextRecords.AddAsync(record);
                await SaveChangesAsync();
                return true;
            }
            catch
            {
                return false;
            }
        }

        public async Task<List<TextRecordModel>> GetTextRecordsAsync()
        {
            return await TextRecords.ToListAsync();
        }
    }

I've also put the whole project on Github, the code is here, in case anyone wants to take a look.

I'm running Xamarin Forms 4.1 and Microsoft.EntityFrameworkCore.Sqlite 2.2.6. To rule out linker issues I have set the linker behaviour to Don't Link but this didn't make any difference. I've also tried adding a line to write a small text file to the DB location prior o this to rule out any file system or permissions issues, and this works without issue.

I have not been able to find any errors in the device logs, but get the following from the stack trace when running in debug mode:

2019-08-16 07:08:01.337 SQLiteTest.iOS[32921:2851415] error: Failed to load AOT module 'data-0x112ed8000.so' in aot-only mode.

=================================================================
    Native Crash Reporting
=================================================================
Got a SIGABRT while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries 
used by your application.
=================================================================

=================================================================
    Basic Fault Adddress Reporting
=================================================================
Memory around native instruction pointer (0x1941610cc):0x1941610bc  fd 7b c1 a8 c0 03 5f d6 10 29 80 d2 01 10 00 d4  .{...._..)......
0x1941610cc  c3 00 00 54 fd 7b bf a9 fd 03 00 91 3f d5 ff 97  ...T.{......?...
0x1941610dc  bf 03 00 91 fd 7b c1 a8 c0 03 5f d6 90 29 80 d2  .....{...._..)..
0x1941610ec  01 10 00 d4 c3 00 00 54 fd 7b bf a9 fd 03 00 91  .......T.{......

=================================================================
    Native stacktrace:
=================================================================
    0x105f84d18 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : (null)
    0x105f7b1d8 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : (null)
    0x1941d44f0 - /usr/lib/system/libsystem_platform.dylib : <redacted>
    0x1941d8a88 - /usr/lib/system/libsystem_pthread.dylib : pthread_kill
    0x1940ba14c - /usr/lib/system/libsystem_c.dylib : abort
    0x1060f3e0c - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : xamarin_find_protocol_wrapper_type
    0x1060d3f34 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : mono_pmip
    0x1060d3f84 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : mono_pmip
    0x105f61a90 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : (null)
    0x105fb72b8 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : mono_pmip
    0x105fb3104 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : mono_pmip
    0x105fee7b0 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : mono_pmip
    0x100b1b094 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : (null)
    0x100b1b1c4 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : (null)
    0x100b1b158 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : (null)
    0x100b1af7c - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : (null)
    0x100ca988c - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : (null)
    0x10129d2bc - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : (null)
    0x105f8bc84 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : mono_pmip
    0x10602e450 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : mono_pmip
    0x105f9767c - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : mono_pmip
    0x105f96b44 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : mono_pmip
    0x105f96c84 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : mono_pmip
    0x105f96c84 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : mono_pmip
    0x105f9c600 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : mono_pmip
    0x105f95610 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : mono_pmip
    0x105fadd70 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : mono_pmip
    0x105f941f8 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : mono_pmip
    0x1013102b4 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : (null)
    0x1009ccabc - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : (null)
    0x10129d2bc - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : (null)
    0x105f8bc84 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : mono_pmip
    0x10602ca98 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : mono_pmip
    0x1060320e4 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : mono_pmip
    0x105f701a0 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : (null)
    0x106103628 - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : xamarin_localized_string_format_9
    0x1009cc9cc - /var/containers/Bundle/Application/06702566-C641-4954-A671-29967CE5DF53/SQLiteTest.iOS.app/SQLiteTest.iOS : (null)
    0x194014fd8 - /usr/lib/system/libdyld.dylib : <redacted>

=================================================================
    Managed Stacktrace:
=================================================================
      at <unknown> <0xffffffff>
      at System.AppDomain:LoadAssemblyRaw <0x00007>
      at System.AppDomain:Load <0x00053>
      at System.AppDomain:Load <0x00047>
      at System.AppDomain:Load <0x0003b>
      at System.Reflection.Assembly:Load <0x0003b>
      at System.Object:runtime_invoke_dynamic <0x0011b>
      at <unknown> <0xffffffff>
      at SQLiteTest.iOS.Application:Main <0x0006b>
      at System.Object:runtime_invoke_dynamic <0x0011b>
=================================================================

What could be causing this and what would be the solution?

Matt G
  • 444
  • 5
  • 23
  • 1
    Did you update the version of iOS or IDE? You can delete the folder bin and obj in iOS project ,then clean and rebuild it . – Lucas Zhang Aug 08 '19 at 07:32
  • Not to my knowledge, however I did subsequently upgrade the version of Xamarin.Forms in all projects (to fix a different issue), and now the problem seems to have gone away...? – Matt G Aug 08 '19 at 08:05
  • Negative, problem has no gone away. – Matt G Aug 09 '19 at 01:14
  • Cleaning and rebuilding made that error go away. But now I keep getting Value cannot be null. Parameter name: key when calling EnsureCreatedAsync – Matt G Aug 09 '19 at 07:18
  • Where and when do you call `EnsureCreatedAsync()`? Looks like it's in the context. And why don't you `await` it? – Gert Arnold Aug 11 '19 at 20:37
  • Yes I’m the context, the reason it’s not awaited is that it’s in the constructor. I’ve moved it to an async method and awaited it still get the same result. – Matt G Aug 11 '19 at 23:01
  • You should show the code (and not an image of it) because it's important to see where and when this is called. – Gert Arnold Aug 12 '19 at 07:05
  • Thanks, I put the whole project up on github and linked to it in the question – Matt G Aug 12 '19 at 07:13
  • 3
    Please read [this](https://meta.stackoverflow.com/q/253915/861716). Questions should be comprehensible without external links. Most users (including me) won't be interested in scrutinizing a complete project on github, even if it's small, let alone trying to run it, probably missing some required dependencies. It should be crystal clear from the question text where and when the failing code is running. – Gert Arnold Aug 12 '19 at 14:52
  • Thanks, I have been away this week and have not had a chance to edit this question although I have done so now. – Matt G Aug 15 '19 at 20:54
  • Well, `EnsureCreatedAsync()` still isn't awaited. And that's your only problem. Why do you use the Async version of it anyway? You must be rock-solid sure that the cde that merily goes on after that call won't address the database before it's even there. Also, you've kicked the can down the road, because now the question is: Where and when do you call `Database()`? – Gert Arnold Aug 15 '19 at 21:29
  • The Database is a singleton and runs from the App class. As per the post, I have tried moving it to an async method and awaiting it and this makes no difference. – Matt G Aug 15 '19 at 21:38
  • Also as the debugger calls out an exception when it hits this line code running after is is not the issue. – Matt G Aug 15 '19 at 21:40
  • This issue is almost certainly caused by a bug in Xamarin Forms – Matt G Aug 15 '19 at 22:15
  • OK then. Deduction time. What if you remove the `EnsureCreated` altogether and run the app when the database is already there? – Gert Arnold Aug 16 '19 at 11:19

1 Answers1

0

This problem is caused by an open issue in EntityFrameworkCore. As a workaround, EFCore SQLite 2.2.6 works with Xamarin.Forms 3.6, or EFCore SQLite 2.1.0 works with Xamarin.Forms 4.1. In either case, as per the above issue, the linker needs to be directed to preserve the EFCore dependencies. This can be done by adding a directive to Main.cs in the IOS project:

[assembly: Preserve (typeof (System.Linq.Queryable), AllMembers = true)]
Matt G
  • 444
  • 5
  • 23
  • If this does not work maybe check [here](https://stackoverflow.com/questions/53521581/xamarin-ios-linker-issue). – Flimtix Oct 28 '21 at 09:27