我正在尝试编写一个通用方法,该方法将加载具有特定 ID 的特定类型的记录。这是一种有效的方法:
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 设计器,将系统中每个 ID 字段的继承属性更改为“覆盖”。
我想要更多的灵活性。所以很自然地,我尝试了反思,并得出以下结论:
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"; }
}
}
从理论上讲,这允许我覆盖 ID 列名称,转换为long
任何整数数据类型都可以,并且我不需要将我的所有 ID 列定义为overrides
.
但
Linq 不喜欢这样。在调用q.Single<T>();
我得到一个运行时错误:
The member 'EISS.Utils.LinqableTable.IDValue' has no supported translation to SQL.
好的,今天我了解到 Linq 在后端做了某种魔术;它不会实例化obj
,只是读取IDValue
属性。所以一定有一些属性需要在IDValue
属性上设置,让 Linq 做它的事情。
但是什么?