C # LINQ to SQL: Refatorando esse método GetByID genérico
Eu escrevi o seguinte método.
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);
}
Basicamente, é um método em uma classe genérica em queT
é uma classe em um DataContex
O método obtém a tabela do tipo de T GetTable
) e verifica a primeira propriedade (sempre sendo o ID) para o parâmetro inserid
O problema é que eu tive que converter a tabela de elementos em uma lista primeiro para executar umGetType
na propriedade, mas isso não é muito conveniente, porque todos os elementos da tabela precisam ser enumerados e convertidos emList
.
Como posso refatorar esse método para evitar umToList
em toda a mesa?
[Atualizar
O motivo pelo qual não consigo executar oWhere
diretamente na tabela é porque recebo esta exceção:
Method 'System.Reflection.PropertyInfo [] GetProperties ()' não tem tradução suportada para SQL.
PorqueGetProperties
não pode ser traduzido para SQL.
[Atualizar
Algumas pessoas sugeriram o uso de uma interface paraT, mas o problema é que oT
será uma classe gerada automaticamente em [DataContextName] .designer.cs e, portanto, não posso implementar uma interface (e não é possível implementar as interfaces para todas essas "classes de banco de dados" do LINQ; além disso, o arquivo será regenerado assim que eu adicionar novas tabelas ao DataContext, perdendo assim todo o dados escritos).
Então, tem que haver uma maneira melhor de fazer isso ...
[Atualizar
Agora implementei meu código comoNeil Williams 'sugestão, mas ainda estou tendo problemas. Aqui estão trechos do código:
Interface
public interface IHasID
{
int ID { get; set; }
}
DataContext [ver código]:
namespace MusicRepo_DataContext
{
partial class Artist : IHasID
{
public int ID
{
get { return ArtistID; }
set { throw new System.NotImplementedException(); }
}
}
}
Método genérico:
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));
}
}
A exceção está sendo lançada nesta linha:return table.SingleOrDefault(e => e.ID.Equals(id));
e a exceção é:
System.NotSupportedException: The member 'MusicRepo_DataContext.IHasID.ID' has no supported translation to SQL.
Solução [Update]:
Com a ajuda deDenis Troller resposta de @ postada e o link para a postagem noCode Rant blog, Finalmente consegui encontrar uma solução:
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();
}