6

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)]
Nic Strong
  • 6,532
  • 4
  • 35
  • 50

4 Answers4

5

Wow, looks like for once I may be able to one-up @MarcGravell!

I had the same problem, then I discovered this answer, which solved the problem for me!

In your case, you would say:

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

and Bob's your uncle!

Community
  • 1
  • 1
Shaul Behr
  • 36,951
  • 69
  • 249
  • 387
  • Thanks. But that will not be "programming to an interface", isn't it? Following is a comment from Scott in http://weblogs.asp.net/scottgu/archive/2007/06/29/linq-to-sql-part-3-querying-our-database.aspx - "Add the interfaces to your LINQ to SQL data model classes. The LINQ to SQL classes are partial classes - which means you could add the interface directly to them." This suggestion does not work in our scenario. Is there a way to make it work? – LCJ Jul 02 '12 at 11:25
4

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
  • 1,026,079
  • 266
  • 2,566
  • 2,900
1

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
  • 111,873
  • 86
  • 233
  • 325
0

Try .OfType<>() as posted here https://stackoverflow.com/a/17734469/3936440, it works for me having the exact same issue.

Community
  • 1
  • 1
ViRuSTriNiTy
  • 5,017
  • 2
  • 32
  • 58