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(); } 

您没有看到它,但编译器将在itemitem.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); }