LinqToSql и абстрактные базовые классы - PullRequest
6 голосов
/ 01 октября 2008

У меня есть несколько сущностей linq, которые наследуют что-то вроде этого:

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
{
}

В общем методе я запрашиваю производные сущности DeviceEnityBase с помощью:

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

, где TEntity имеет ограничение, то есть DeviceEntityBase. Этот запрос всегда завершается с ошибкой InvalidOperationException с сообщением «Член класса DeviceEntityBase.DeviceId не сопоставлен». Даже если я добавлю некоторую информацию о сопоставлении в абстрактный базовый класс с помощью

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

Ответы [ 4 ]

5 голосов
/ 21 февраля 2011

Ух ты, похоже, на этот раз я смогу поднять @MarcGravell!

У меня была такая же проблема, затем я обнаружил этот ответ , который решил проблему для меня!

В вашем случае вы бы сказали:

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

и Боб твой дядя!

4 голосов
/ 01 октября 2008

LINQ-to-SQL имеет некоторую поддержку наследования через дискриминатор ( здесь , здесь ), но вы можете запрашивать только те классы, которые определены в модели LINQ - т.е. самих классов данных и (что, возможно, более важно для этого примера) сам запрос должен быть сформулирован в терминах классов данных: хотя TEntity является классом данных, он знает, что свойство здесь объявлено на базе сущностей .

Одним из вариантов могут быть динамические выражения; если сами классы объявили свойство (то есть потеряли базовый класс, но сохранили интерфейс), но это не тривиально.

Работа над выражением будет выглядеть примерно так, как показано ниже, отметив, что вы можете либо передать строку в качестве аргумента, либо получить первичный ключ посредством отражения (если оно приписано):

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);
}
1 голос
/ 01 октября 2008

Этот тип иерархического отображения невозможен с LinqToSql. Отображение настроено так, что оно не может отображаться на свойства в базовых классах. Я занимался этим пару месяцев, когда он впервые вышел. Лучшее решение - это использовать структуру сущностей. Это дает вам гораздо больше гибкости при создании вашей объектной модели. Это позволит вам сделать именно то, что вы пытаетесь сделать здесь.

Вот некоторая информация о структуре объекта: Статья MSDN

0 голосов
/ 26 января 2017

Попробуйте .OfType<>() как написано здесь https://stackoverflow.com/a/17734469/3936440, у меня работает точно такая же проблема.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...