Escribí el siguiente método.C# LINQ to SQL: Refactorizando este método Generic GetByID
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);
}
Básicamente se trata de un método en una clase genérica donde T
es una clase en un DataContext.
El método obtiene la tabla del tipo de T (GetTable
) y comprueba la primera propiedad (que siempre es la ID) del parámetro ingresado.
El problema con esto es que tuve que convertir la tabla de elementos a una lista primero para ejecutar un GetType
en la propiedad, pero esto no es muy conveniente porque todos los elementos de la tabla deben enumerarse y convertirse en un List
.
¿Cómo puedo refactorizar este método para evitar un ToList
en toda la tabla?
[Actualización]
La razón por la que no puede ejecutar el Where
directamente sobre la mesa es porque recibo esta excepción:
método 'System.Reflection.PropertyInfo [] GetProperties () 'no tiene traducción soportada a SQL.
Porque GetProperties
no se puede traducir a SQL.
[Actualización]
Algunas personas han sugerido el uso de una interfaz para T, pero el problema es que el parámetro T
será una clase que se genera en automático .designer.cs [DataContextName], y por lo tanto no puedo implementar una interfaz (y no es factible implementar las interfaces para todas estas "clases de base de datos" de LINQ, y también, el archivo se regenerará una vez que agregue nuevas tablas al DataContext, perdiendo así todo el datos escritos).
Por lo tanto, tiene que haber una mejor manera de hacer esto ...
[Actualización]
ahora han puesto en práctica mi código como Neil Williams 'sugerencia, pero todavía estoy teniendo problemas .He aquí algunos fragmentos de código:
Interfaz:
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));
}
}
La excepción está siendo lanzado en esta línea: return table.SingleOrDefault(e => e.ID.Equals(id));
y la excepción es:
System.NotSupportedException: The member 'MusicRepo_DataContext.IHasID.ID' has no supported translation to SQL.
[Actualización] Solución:
Con la ayuda de Denis Troller 's publicado respuesta y el enlace a la publicación en el Code Rant blog, finalmente logré encontrar una solución:
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();
}
Usted no necesita preocuparse por el diseñador genera archivos o el diseñador edmx sobre escribirlos .. que no implementan la interfaz en el archivo del diseñador que .. Escribiré una clase parcial para las entidades que implementan la interfaz. – meandmycode
Pero eso significa que debo hacer que cada "clase de db" implemente esta interfaz, ¿no? –
Sí, lo haría, pero es un trabajo de una sola vez y luego su código será mucho más robusto. –