public T GetByID(int id)
{
var dbcontext = DB;
var table = dbcontext.GetTable<T>();
return table.ToList().SingleOrDefault(e => Convert.ToInt16(e.GetType().GetProperties().First().GetValue(e, null)) == id);
}
基本上,这是一个泛型类中的方法,其中T
是DataContext中的一个类。
该方法通过类型T(GetTable
)获取表,然后检查第一个属性(始终为ID)是否符合输入参数。
问题在于,我必须先将元素表转换为列表,才能对属性执行GetType
,但这并不方便,因为必须枚举和转换表中的所有元素为List
。
如何重构此方法,以避免在整个表上使用ToList
?
[更新]
我无法直接在表格上执行Where
的原因是我收到了以下异常:
方法“System.Reflection.PropertyInfo [] GetProperties()”没有受支持的 SQL 翻译。
因为GetProperties
无法被翻译成SQL。
[更新]
有些人建议为T使用接口,但问题是T
参数将是在[DataContextName].designer.cs中自动生成的类,因此我不能使其实现接口(并且为LINQ的所有这些“数据库类”实现接口不可行;而且一旦我向DataContext添加新表,则文件将重新生成,从而丢失所有编写的数据)。
因此,必须有更好的方法来解决这个问题...
[更新]
我现在已经按照Neil Williams的建议实现了我的代码,但仍然存在问题。以下是代码摘录:接口:
public interface IHasID
{
int ID { get; set; }
}
DataContext [查看代码]:
namespace MusicRepo_DataContext
{
partial class Artist : IHasID
{
public int ID
{
get { return ArtistID; }
set { throw new System.NotImplementedException(); }
}
}
}
通用方法:
public class DBAccess<T> where T : class, IHasID,new()
{
public T GetByID(int id)
{
var dbcontext = DB;
var table = dbcontext.GetTable<T>();
return table.SingleOrDefault(e => e.ID.Equals(id));
}
}
这个异常是在这一行代码抛出的:return table.SingleOrDefault(e => e.ID.Equals(id));
异常信息如下:
System.NotSupportedException: 该成员 'MusicRepo_DataContext.IHasID.ID' 没有受支持的 SQL 翻译。
[更新] 解决方案:
在Denis Troller发布的回答和Code Rant blog上的链接的帮助下,我最终找到了解决方案:
public static PropertyInfo GetPrimaryKey(this Type entityType)
{
foreach (PropertyInfo property in entityType.GetProperties())
{
ColumnAttribute[] attributes = (ColumnAttribute[])property.GetCustomAttributes(typeof(ColumnAttribute), true);
if (attributes.Length == 1)
{
ColumnAttribute columnAttribute = attributes[0];
if (columnAttribute.IsPrimaryKey)
{
if (property.PropertyType != typeof(int))
{
throw new ApplicationException(string.Format("Primary key, '{0}', of type '{1}' is not int",
property.Name, entityType));
}
return property;
}
}
}
throw new ApplicationException(string.Format("No primary key defined for type {0}", entityType.Name));
}
public T GetByID(int id)
{
var dbcontext = DB;
var itemParameter = Expression.Parameter(typeof (T), "item");
var whereExpression = Expression.Lambda<Func<T, bool>>
(
Expression.Equal(
Expression.Property(
itemParameter,
typeof (T).GetPrimaryKey().Name
),
Expression.Constant(id)
),
new[] {itemParameter}
);
return dbcontext.GetTable<T>().Where(whereExpression).Single();
}