database - transact - LINQ to SQL para tablas autorreferenciales
linqpad sql to linq (4)
Bueno, aquí hay una terrible implementación apresurada con LINQ. No uses esto :-)
public IQueryable GetCategories(Category parent)
{
var cats = (parent.Categories);
foreach (Category c in cats )
{
cats = cats .Concat(GetCategories(c));
}
return a;
}
Tengo una tabla de Categorías autorreferencial. Cada categoría tiene un ID de categoría, un ID de categoría de padre, un nombre de categoría, etc. Y cada categoría puede tener cualquier cantidad de subcategorías, y cada una de esas subcategorías puede tener cualquier cantidad de subcategorías, y así sucesivamente. Entonces, básicamente, el árbol puede tener niveles X profundos.
Entonces los Productos están asociados a categorías (sub) hoja. ¿Hay alguna forma de obtener todos los Productos para una Categoría dada (que serían todos los productos asociados a todos sus descendientes de hojas) usando LINQ to SQL?
Esto se siente como un problema recursivo. ¿Es mejor usar un Procedimiento almacenado en su lugar?
El enfoque de rendimiento es crear un desencadenador de inserción / modificación / eliminación que mantiene una tabla completamente diferente que contiene pares de nodo-antepasado para todos los antepasados de todos los nodos. De esta manera, la búsqueda es O (N).
Para usarlo para obtener todos los productos que pertenecen a un nodo y todos sus descendientes, puede seleccionar todos los nodos de categoría que tengan su nodo de destino como antecesor. Después de esto, simplemente selecciona cualquier producto que pertenezca a cualquiera de estas categorías.
La forma en que manejo esto es mediante el uso de algunos métodos de extensión (filtros). He escrito un código de muestra de un proyecto en el que he implementado esto. Mire específicamente las líneas donde estoy poblando un objeto ParentPartner y una Lista de Subpartes.
public IQueryable<Partner> GetPartners()
{
return from p in db.Partners
select new Partner
{
PartnerId = p.PartnerId,
CompanyName = p.CompanyName,
Address1 = p.Address1,
Address2 = p.Address2,
Website = p.Website,
City = p.City,
State = p.State,
County = p.County,
Country = p.Country,
Zip = p.Zip,
ParentPartner = GetPartners().WithPartnerId(p.ParentPartnerId).ToList().SingleOrDefault(),
SubPartners = GetPartners().WithParentPartnerId(p.PartnerId).ToList()
};
}
public static IQueryable<Partner> WithPartnerId(this IQueryable<Partner> qry, int? partnerId)
{
return from t in qry
where t.PartnerId == partnerId
select t;
}
public static IQueryable<Partner> WithParentPartnerId(this IQueryable<Partner> qry, int? parentPartnerId)
{
return from p in qry
where p.ParentPartner.PartnerId == parentPartnerId
select p;
}
No creo que linq-to-sql tenga una buena respuesta a este problema. Como está utilizando sql server 2005, puede usar CTE para realizar consultas jerárquicas. Ya sea un procedimiento almacenado o una consulta en línea (usando DataContext.ExecuteQuery) hará el truco.