Я написал следующий метод.
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
) и проверяет наличие первого свойства (всегда являющегося идентификатором) для введенного параметра.
Проблема в том, что мне пришлось сначала преобразовать таблицу элементов в список, чтобы выполнить GetType
для свойства, но это не очень удобно, поскольку все элементы таблицы должны быть перечислены и преобразованы в List
.
Как я могу изменить этот метод, чтобы избежать ToList
на всей таблице?
[Update]
Причина, по которой я не могу выполнить Where
непосредственно в таблице, заключается в том, что я получаю это исключение:
Метод 'System.Reflection.PropertyInfo [] GetProperties ()' не поддерживает перевод на SQL.
Поскольку GetProperties
не может быть переведено в SQL.
[Update]
Некоторые люди предлагают использовать интерфейс для T , но проблема в том, что параметр T
будет классом, который автоматически создается в [DataContextName] .designer.cs и, следовательно, я не могу заставить его реализовать интерфейс (и нереально реализовать интерфейсы для всех этих «классов баз данных» LINQ; кроме того, файл будет сгенерирован заново, как только я добавлю новые таблицы в DataContext, таким образом потеряя все письменные данные).
Итак, должен быть лучший способ сделать это ...
[Update]
Я сейчас реализовал свой код, как Нил Уильямс ', но у меня все еще есть проблемы. Вот выдержки из кода:
Интерфейс:
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: The
member
'MusicRepo_DataContext.IHasID.ID' has
no supported translation to SQL.
[Обновление] Решение:
С помощью сообщения Дениса Троллера и ссылки на пост в блоге Code Rant мне наконец удалось найти решение:
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();
}