SQLite.NET -Система.NotSupportedException: не удается скомпилировать: параметр

Я использую SQLite.NET Async (http://www.nuget.org/packages/SQLite.Net.Async-PCL/) в проекте Xamarin iOS, но у меня возникла проблема с использованием запросов предиката таблицы.

в любое время, когда я использую метод 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: Проблема, похоже, связана с тем, что мои методы являются общими. Если я изменю их на конкретные для модели "соединение".Таблица .Где.(..- это работает. Будут ли общие методы не работать?

правка #2: Я добавил ограничение "class" на T, чтобы пойти вместе с существующим " IDataModel, new ()" ограничения, и это, кажется, исправило проблему...Это имеет смысл?

2 ответов


имеет смысл добавить 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 поставщик запросов, по-видимому, может правильно перевести.


проблема, я полагаю, будет в том, что компилятор не знает, что элемент имеет идентификатор свойства.

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