views:

177

answers:

2

I'm trying to use DbLinq with a SQLite database, but I'm running into a problem when I try to cast an ITable as a Queryable<TEntity>.

There is a known bug in DbLinq (Issue 211), which might be the source of my problem, but I wanted to make sure my code is sound and, if it is, find out if there might be something I can do to work around the bug.

Here is the generic repository method that attempts to do the cast:

public IQueryable<TEntity> GetAll()
{
    return Table.Cast<TEntity>(); // Table is an ITable
}

This compiles, but if I pass in the interface IPerson for TEntity and the type of the entities in the table is Person (where Person : IPerson), I'm getting this error from DbLinq:

S0133: Implement QueryMethod Queryable.Cast.

Why am I trying to do this?

I have a library project that doesn't know the type of the entity until runtime, but it does know the interface for the entity. So, I'm trying to cast to the interface type so that my library project can consume the data.

Questions:

  1. Am I attempting an impossible cast or is this definitely a bug in DbLinq?
  2. How else could I go about solving my problem?

Update

I reworked my repository class so it now takes a TEntity and a TEntityBase, where TEntity is the actual type of the entity, and TEntityBase is the interface that I'm trying to cast to. Importantly, I now have the following where clause in my class definition:

where TEntity : class, TEntityBase

This allows me to store my Table property as a Table<TEntity> instead of an ITable, which allows me to use AsEnumerable() (as Stephen suggested). Here is the revised method:

public IEnumerable<TEntityBase> GetAll()
{
    return Table.AsEnumerable().Select(e => (TEntityBase)e);
}

And so far, that seems to do the trick.

+2  A: 

It sounds like a bug, but understand that implementing a LINQ provider is an absolutely huge endeavor. Even (Microsoft's) LINQ to SQL and LINQ to Entities have their own restrictions on exactly which LINQ queries/operations they support or do not support.

If returning IEnumerable<T> is acceptable, then you could work around the lack of support for Queryable.Cast by calling AsEnumerable before calling Cast. However, this restricts how your DAL can be used: since IQueryable<T> is no longer returned, further queries (e.g., Where clauses) won't be passed through to the DB layer.

Stephen Cleary
Thanks, Stephen! I think returning IEnumerable<T> would be acceptable for my purposes, but I'm not seeing a method or an extension called `AsEnumerable()` on my `ITable` object. Could I be missing a namespace reference?
DanM
+2  A: 

I agree it sounds like a bug. You could try the following which will do the same thing

return Table.Select<TEntity>(tbl => (TEntity)tbl)

You might have to add a where : ITable to the method definition as well.

Ben Robinson
Thanks, Ben. Alas, same problem as with Stephen's answer. `Select()` does not appear to be available for an ITable.
DanM