praeclarum / sqlite-net

Simple, powerful, cross-platform SQLite client and ORM for .NET
MIT License
4.02k stars 1.42k forks source link

why we can't use type `struct` as the table data type while using nuget sqlite-net-pcl 1.8.116 #1075

Open jessiezh0320 opened 2 years ago

jessiezh0320 commented 2 years ago

If I used type struct as the table data type,I could create and insert some items into my database ,but if I queried the items from the database, my app throws an error System.ArgumentException Message=method arguments are incompatible.

I could reproduce this problem with nuget sqlite-net-pcl 1.8.116., but if I used lower version (e.g. 1.7.335), there is no such error. You can try to repreduce this problem with official sample here: https://docs.microsoft.com/en-us/samples/xamarin/xamarin-forms-samples/todo/

Steps:

1.Try to create a new Model with type struct ; 2.replace class TodoItem with the new model we create above, in page TodoListPage.xaml.cs, the app will try to add a new item in function OnItemAdded 3.Aftern inserting a new item, if we come back to page TodoListPage, the function OnAppearing() which will read back the new added item. Here the app will throw such error.

bobwhitten commented 2 years ago

I have this too., but only noticed now. Rolling back to 1.7.335 makes it work again. Should I update my struct to class?

gindemit commented 2 years ago

I also have the same issue in Unity editor switched to Android platform. When I use struct for the data, I get following error:

ArgumentException: method arguments are incompatible System.Delegate.CreateDelegate (System.Type type, System.Object firstArgument, System.Reflection.MethodInfo method, System.Boolean throwOnBindFailure, System.Boolean allowClosed) (at <695d1cc93cca45069c528c15c9fdd749>:0) System.Delegate.CreateDelegate (System.Type type, System.Object firstArgument, System.Reflection.MethodInfo method) (at <695d1cc93cca45069c528c15c9fdd749>:0) SQLite.FastColumnSetter.CreateTypedSetterDelegate[ObjectType,ColumnMemberType] (SQLite.TableMapping+Column column, System.Func3[T1,T2,TResult] getColumnValue) (at Assets/_ThirdParty/Runtime/SQLite/SQLite.cs:3575) SQLite.FastColumnSetter.CreateNullableTypedSetterDelegate[ObjectType,ColumnMemberType] (SQLite.TableMapping+Column column, System.Func3[T1,T2,TResult] getColumnValue) (at Assets/_ThirdParty/Runtime/SQLite/SQLite.cs:3562) SQLite.FastColumnSetter.GetFastSetter[T] (SQLite.SQLiteConnection conn, SQLite.TableMapping+Column column) (at Assets/_ThirdParty/Runtime/SQLite/SQLite.cs:3400) SQLite.SQLiteCommand+d__121[T].MoveNext () (at Assets/_ThirdParty/Runtime/SQLite/SQLite.cs:3029) System.Collections.Generic.List1[T]..ctor (System.Collections.Generic.IEnumerable1[T] collection) (at <695d1cc93cca45069c528c15c9fdd749>:0) System.Linq.Enumerable.ToList[TSource] (System.Collections.Generic.IEnumerable1[T] source) (at <351e49e2a5bf4fd6beabb458ce2255f3>:0) SQLite.SQLiteCommand.ExecuteQuery[T] () (at Assets/_ThirdParty/Runtime/SQLite/SQLite.cs:2975) SQLite.SQLiteConnection.Query[T] (System.String query, System.Object[] args) (at Assets/_ThirdParty/Runtime/SQLite/SQLite.cs:1007)

SQLite version: v1.8.116 from 3 September 2021

Changing the struct to sealed class fixes the issue.

duanrui71 commented 1 year ago

这是因为FastColumnSetter中的CreateTypedSetterDelegate函数调用了Delegate.CreateDelegate. 当第一个类型是Value类型时,CreateDelegate会失败.

// 当ObjectType 是Value类型时,无法创建Delegate
var setProperty = (Action<ObjectType, ColumnMemberType>)Delegate.CreateDelegate (
                        typeof (Action<ObjectType, ColumnMemberType>), null,
                        column.PropertyInfo.GetSetMethod ());

                return (o, stmt, i) => {
                    var colType = SQLite3.ColumnType (stmt, i);
                    if (colType != SQLite3.ColType.Null)
                        setProperty.Invoke ((ObjectType)o, getColumnValue.Invoke (stmt, i));
                };