FluentConfigurationException exception on Xamarin.Forms with Sqlite
Hi guys,
Recently I tried to port a logic from a WPF application to a Xamarin.Forms app. Both are using NHibernate with SQLite.
At first, it seemed easy but I got a lot of errors while creating the session factory in the Xamarin.Forms. I read some posts about writing my own Mono SQLite driver, so I did based on an example. I also added a reference to Mono.Data.Sqlite in my Android project and get rid of a lots of "cannot load DLL" exceptions.
But now, I still have a FluentConfigurationException while creating the session factory. The same code works well in a WPF application with SQLite.
E/mono-rt (11189): [ERROR] FATAL UNHANDLED EXCEPTION: FluentNHibernate.Cfg.FluentConfigurationException: An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.
E/mono-rt (11189):
E/mono-rt (11189): ---> System.FieldAccessException: Field `XXX.Domain.Common.BaseClasses.Entity:<Id>k__BackingField' is inaccessible from method `(wrapper dynamic-method) XXX.Domain.Audits.CashDrawerOpening: (object)'
The Entity class is indeed composed of a private backing field and there is no problem in WPF.
public abstract class Entity
{
protected long Id { get; }
public static class Expressions<T> where T : Entity
{
public static readonly Expression<Func<T, object>> Id = x => x.Id;
}
// rest of the implementation
}
The only difference between both is the SQLiteConfiguration in WPF between MonoSqliteConfiguration in Xamarin.Forms
WPF Session Factory builder :
return Fluently.Configure()
.Database(SQLiteConfiguration.Standard.ConnectionString(connectionString))
.Mappings(m => m.FluentMappings
.AddFromAssembly(Assembly.GetExecutingAssembly())
.Conventions.Add(
ForeignKey.EndsWith("Id"),
ConventionBuilder.Property.When(criteria => criteria.Expect(x => x.Nullable, Is.Not.Set), x => x.Not.Nullable()))
.Conventions.Add<RelationshipConventions>()
.Conventions.Add<IdConvention>()
)
.ExposeConfiguration(x => new SchemaUpdate(x).Execute(true, true))
.BuildSessionFactory();
Xamarin.Forms Session Factory builder :
return Fluently.Configure()
.Database(MonoSqliteConfiguration.Standard.ConnectionString(connectionString))
.Mappings(m => m.FluentMappings
.AddFromAssembly(Assembly.GetExecutingAssembly())
.Conventions.Add(
ForeignKey.EndsWith("Id"),
ConventionBuilder.Property.When(criteria => criteria.Expect(x => x.Nullable, Is.Not.Set), x => x.Not.Nullable()))
.Conventions.Add<RelationshipConventions>()
.Conventions.Add<IdConvention>()
)
.ExposeConfiguration(x => new SchemaUpdate(x).Execute(true, true))
.BuildSessionFactory();
The implementation of the MonoSqliteConfiguration can be found here https://stackoverflow.com/questions/7626251/using-nhibernate-and-mono-data-sqlite
Package informations :
- FluentNHibernate : 3.1.0
- NHibernate : 5.3.5
- Xamarin.Forms : 5.0.0.1931
- Xamarin.Android SDK : 11.1.0.26
- Target Android API 29
Do you have any idea of what is going on ?
Thank you for your help ! :)
Michael
[EDIT]
After defining the Id property as protected with a setter, it works.
protected virtual long Id { get; set; }
So, there is a problem with the reflection between an WPF app (netFramework 4.8) and the mono-rt ?
It seems that you would probably need to switch default access strategy to property.