tags:

views:

417

answers:

2

I have some linq entities that inherit something like this:

public abstract class EntityBase { public int Identifier { get; } }

public interface IDeviceEntity { int DeviceId { get; set; } }

public abstract class DeviceEntityBase : EntityBase, IDeviceEntity
{
  public abstract int DeviceId { get; set; }
}

public partial class ActualLinqGeneratedEntity : DeviceEntityBase
{
}

In a generic method I am querying DeviceEnityBase derived entities with:

return unitOfWork.GetRepository<TEntity>().FindOne(x => x.DeviceId == evt.DeviceId);

where TEntity has a contraint that is it a DeviceEntityBase. This query is always failing with an InvalidOperationException with the message "Class member DeviceEntityBase.DeviceId is unmapped". Even if I add some mapping info in the abstract base class with

[Column(Storage = "_DeviceId", DbType = "Int", Name = "DeviceId", IsDbGenerated = false, UpdateCheck = UpdateCheck.Never)]
+1  A: 

This kind of heirarchial mapping isnot possible with LinqToSql. The the mapping is setup it cannot map to properties in base classes. I went around on this for a couple of months when it first came out. The best solution is to use the entity framework. It gives you much more flexibility with creating your object model. It will allow you to do exactly what your trying to do here.

Here is some information on the entity framework: MSDN Article

Micah
+2  A: 

LINQ-to-SQL has some support for inheritance via a discriminator (here, here), but you can only query on classes that are defined in the LINQ model - i.e. data classes themselves, and (more perhaps importantly for this example) the query itself must be phrased in terms of data classes: although TEntity is a data class, it knows that the property here is declared on the entity base.

One option might be dynamic expressions; it the classes themselves declared the property (i.e. lose the base class, but keep the interface) - but this isn't trivial.

The Expression work would be something like below, noting that you might want to either pass in the string as an argument, or obtain the primary key via reflection (if it is attributed):

static Expression<Func<T, bool>> BuildWhere<T>(int deviceId) {
    var id = Expression.Constant(deviceId, typeof(int));
    var arg = Expression.Parameter(typeof(T), "x");
    var prop = Expression.Property(arg, "DeviceId");
    return Expression.Lambda<Func<T, bool>>(
        Expression.Equal(prop, id), arg);
}
Marc Gravell