Я пытаюсь написать универсальный метод, который будет загружать запись определенного типа с определенным идентификатором. Вот один способ, который работает:
public abstract class LinqedTable<T> where T : LinqableTable {
public static T Get(long ID) {
DataContext context = LinqUtils.GetDataContext<T>();
var q = from obj in context.GetTable<T>()
where obj.ID == ID
select obj;
return q.Single<T>();
}
}
public abstract class LinqableTable {
public abstract long ID { get; set; }
}
Вы можете игнорировать вызов LinqUtils.GetDataContext<T>()
; это служебная функция, с которой мне приходится иметь дело с тем фактом, что в моей программе есть несколько контекстов данных. Дело в том, что теперь я могу объявить любой из моих классов подклассами LinqableTable
и легко создать экземпляр записи этой таблицы, просто вызвав LinqedTable<MyType>.Get(ID)
.
Однако это имеет некоторые ограничения. Во-первых, это заставляет все мои таблицы иметь I
поле идентификатора типа long
с именем ID
. Во-вторых, поскольку я использую абстрактный метод, я вынужден перейти к конструктору O / R и изменить свойство наследования каждого поля идентификатора в моей системе на «переопределить».
Я хочу больше гибкости, чем это. Естественно, я попробовал рефлексию и выдал следующее:
public abstract class LinqedTable<T> where T : LinqableTable {
public static T Get(long ID) {
DataContext context = LinqUtils.GetDataContext<T>();
var q = from obj in context.GetTable<T>()
where obj.IDValue == ID
select obj;
return q.Single<T>();
}
}
public abstract class LinqableTable {
internal long IDValue {
get { return (long)IDProperty.GetValue(this, null); }
set { IDProperty.SetValue(this, value, null); }
}
internal PropertyInfo IDProperty {
get { return this.GetType().GetProperty(IDPropertyName); }
}
internal protected virtual string IDPropertyName {
get { return "ID"; }
}
}
Теоретически, это позволяет мне переопределить имя столбца идентификатора, приведение к long
должно быть в порядке с любым целым типом данных, и мне не нужно определять все мои столбцы идентификатора как overrides
.
НО
Линку это не нравится. При вызове q.Single<T>();
я получаю ошибку времени выполнения:
The member 'EISS.Utils.LinqableTable.IDValue' has no supported translation to SQL.
Хорошо, сегодня я узнал, что Linq делает какую-то магию на заднем конце; он не создает экземпляр obj
, а просто читает свойство IDValue
. Должно быть, в свойстве IDValue
должен быть установлен некоторый атрибут, который позволяет Linq делать свое дело.
а что?