8

我在 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<EventDataModel>.Where(...”它会起作用。通用方法会不起作用吗?

编辑#2:我在 T 上添加了一个 'class' 约束,以配合现有的 'IDataModel, new()' 约束,这似乎解决了这个问题......这有意义吗?

4

3 回答 3

12

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

你看不到它,但编译器会在itemand之间插入一个强制转换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 查询提供程序显然可以正确翻译。

于 2014-02-23T23:48:53.590 回答
4

我认为问题在于编译器不知道该项目具有属性 ID。

return await connection.Table<T>()
        .Where(item => **item.Id** == id)
        .FirstOrDefaultAsync();

您可以使用 Id 字段创建一个接口并使用 where 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);
}
于 2014-02-22T23:25:20.280 回答
0

对于那些想知道什么是class约束的人T,​​以下是方法签名 Task<T> GetAsync<T>(int id) where T : class, IDbModel, new();

于 2019-09-06T05:29:52.190 回答