SQLite.NET – System.NotSupportedException:无法编译:参数
我在Xamarin iOS项目中使用SQLite.NET Async( http://www.nuget.org/packages/SQLite.Net.Async-PCL/ ),但我在使用表谓词查询时遇到问题。
无论何时我使用下面的Get方法,这很简单,我收到一个exception,表达式无法编译,System.NotSupportedException:无法编译:参数。
但是,如果我使用低级查询,就像使用GetQuery方法一样,它可以正常工作。 在我的表的定义或阻止sqlite.net编译表达式的方法中,我做错了吗?
public interface IDataModel { [PrimaryKey, AutoIncrement] int Id { get; set; } } public class BaseDataModel : IDataModel { [PrimaryKey] public virtual int Id { get; set; } } [Table("Event")] public class EventDataModel : BaseDataModel { public string Name { get; set; } public int OrganizationId { get; set; } public DateTime StartDate { get; set; } public DateTime? EndDate { get; set; } public bool Active { get; set; } } public class DataService : IDataService where T : IDataModel, new() { public virtual async Task Get(int id) { var connection = await GetConnection(); return await connection.Table() .Where(item => item.Id == id) .FirstOrDefaultAsync(); } public virtual async Task GetQuery(int id) { var connection = await GetConnection(); return (await connection.QueryAsync("SELECT * FROM Event WHERE Id = ?", id)) .FirstOrDefault(); } }
编辑#1:问题似乎与我的方法是通用的事实有关。 如果我将它们更改为特定的模型“connection.Table .Where(…”它的工作原理。generics方法不起作用吗?
编辑#2:我在T上添加了一个“类”约束,以配合现有的’IDataModel,new()’约束,这似乎解决了这个问题……这有意义吗?
添加class
约束可以解决问题。
当你写:
public virtual async Task Get(int id) where T : IDataModel, new() { var connection = await GetConnection(); return await connection.Table () .Where(item => item.Id == id) .FirstOrDefaultAsync(); }
您没有看到它,但编译器将在item
和item.Id
之间插入一个item.Id
。
也就是说,编译器实际写的是:
public virtual async Task Get(int id) where T : IDataModel, new() { var connection = await GetConnection(); return await connection.Table () .Where(item => ((IDataModel)item).Id == id) .FirstOrDefaultAsync(); }
插入该强制转换因为如果T
是值类型则必须插入。
很容易想象SQLite.net的查询提供程序没有正确处理插入的转换,因为这样做并不简单。
添加class
约束允许编译器避免插入该转换,从而产生一个更简单的表达式,SQLite.net查询提供程序显然可以正确转换。
我想,问题是编译器不知道该项具有属性Id。
return await connection.Table() .Where(item => **item.Id** == id) .FirstOrDefaultAsync();
您可以使用Id字段创建一个接口并使用T:
public interface ITable { int Id { get; set; } } public virtual async Task Get(int id) where T : ITable { ...
然后你可能应该只使用FindAsync:
public virtual async Task Get(int id) { var connection = await GetConnection(); return await connection.FindAsync (id); }