SQLite.NET - System.NotSupportedException: Cannot compile: Parameter

It does make sense that adding a class constraint would solve the issue.

When you write:

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

You do not see it, but the compiler will insert a cast between item and item.Id.

That is, what the compiler actually writes is:

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

That cast is inserted because it would be necessary if T is a value type.

It is easy to imagine that the query provider for SQLite.net does not handle that inserted cast correctly, as doing so is not trivial.

Adding the class constraint allows the compiler to avoid inserting that cast, resulting in a simpler expression that the SQLite.net query provider apparently can translate correctly.


The problem, I assume, would be that the compiler doesn't know the item has property Id.

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

You could create an interface with the Id field and use where T:

public interface ITable
{
    int Id { get; set; }
}

    public virtual async Task<T> Get(int id) where T : ITable
    {
       ... 

Then again you probably should just use FindAsync:

public virtual async Task<T> Get(int id)
{
    var connection = await GetConnection();

    return await connection.FindAsync<T>(id);
}