我在Xamarin iOS项目中使用SQLite.NET Async(http://www.nuget.org/packages/SQLite.Net.Async-PCL/),但是我在使用表谓词查询时遇到了问题。
任何时候我都使用下面的Get方法,这很简单,我收到一个异常,表达式无法编译,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<T> : IDataService<T> where T : IDataModel, new()
{
public virtual async Task<T> Get(int id)
{
var connection = await GetConnection();
return await connection.Table<T>()
.Where(item => item.Id == id)
.FirstOrDefaultAsync();
}
public virtual async Task<T> GetQuery(int id)
{
var connection = await GetConnection();
return (await connection.QueryAsync<T>("SELECT * FROM Event WHERE Id = ?", id))
.FirstOrDefault();
}
}
编辑#1: 问题似乎与我的方法是通用的这一事实有关。如果我将它们更改为特定的模型“connection.Table&lt; EventDataModel&gt; .Where(...”它的工作原理。泛型方法不起作用吗?
编辑#2: 我在T上添加了一个“类”约束,以配合现有的'IDataModel,new()'约束,这似乎解决了这个问题......这有意义吗?
答案 0 :(得分:11)
添加class
约束可以解决问题。
当你写:
public virtual async Task<T> Get(int id)
where T : IDataModel, new()
{
var connection = await GetConnection();
return await connection.Table<T>()
.Where(item => item.Id == id)
.FirstOrDefaultAsync();
}
您没有看到它,但编译器会在item
和item.Id
之间插入一个强制转换。
也就是说,编译器实际写的是:
public virtual async Task<T> Get(int id)
where T : IDataModel, new()
{
var connection = await GetConnection();
return await connection.Table<T>()
.Where(item => ((IDataModel)item).Id == id)
.FirstOrDefaultAsync();
}
插入了强制转换,因为如果T
是值类型,则必须使用。
很容易想象SQLite.net的查询提供程序没有正确处理插入的转换,因为这样做并不容易。
添加class
约束允许编译器避免插入该转换,从而产生一个更简单的表达式,SQLite.net查询提供程序显然可以正确转换。
答案 1 :(得分:4)
我认为问题在于编译器不知道该项具有属性Id。
return await connection.Table<T>()
.Where(item => **item.Id** == id)
.FirstOrDefaultAsync();
您可以使用Id字段创建一个界面,并使用T:
public interface ITable
{
int Id { get; set; }
}
public virtual async Task<T> Get(int id) where T : ITable
{
...
然后你可能应该只使用FindAsync:
public virtual async Task<T> Get(int id)
{
var connection = await GetConnection();
return await connection.FindAsync<T>(id);
}
答案 2 :(得分:0)
对于那些想知道对class
的{{1}}约束是什么的人,以下是方法签名
T