framework c# entity-framework nhibernate entity-framework-6

c# - nhibernate vs entity framework core



Agregar condición a la asignación para la recopilación de elementos secundarios en Entity Framework 6 similar al "dónde" de NHibernate (1)

En NHibernate, hay un mapeo where que le permite especificar una condición en una asignación de propiedad que afecta cómo se extrae de la base de datos. Por ejemplo, si quisiera implementar una eliminación suave y excluir todos los elementos eliminados de un conjunto, podría asignarlo de la siguiente manera:

FluentNHibernate

// in class ParentMap : ClassMap HasMany(x => x.Children).Where("IsDeleted = 0");

Hbm.Xml

<class name="Parent" table="[Parents]"> <bag cascade="all" lazy="true" name="Children" where="IsDeleted = 0"> <!-- rest of map here --> </bag> </class>

¿Hay algo similar en Entity Framework 6?

Lo más parecido que encontré fue una biblioteca llamada EntityFramework.Filters , que le permite agregar filtros globales para las propiedades, pero no parece funcionar cuando esa propiedad es una colección.

Para dar un mejor ejemplo de por qué es necesario un mapeo como este, digamos que tengo una clase que tiene una colección de objetos que tienen una relación de entidad hijo recursiva (es decir, una colección de objetos del mismo tipo). Siguen esta estructura básica:

public class ReportOutline { public long Id { get; set; } public string Title { get; set; } public string Author { get; set; } public virtual ICollection<OutlineItem> OutlineItems { get; set; } } public class OutlineItem { public long Id { get; set; } public string Name { get; set; } public long ReportOutlineId { get; set; } public long? ParentOutlineItemId { get; set; } public virtual ReportOutline ReportOutline { get; set; } public virtual OutlineItem ParentOutlineItem { get; set; } public virtual ICollection<OutlineItem> OutlineItems { get; set; } }

Y estos se asignan con la API EF fluida como esta:

modelBuilder.Entity<ReportOutline>() .HasKey(o => o.Id) .HasMany(o => o.OutlineItems) .WithRequired(i => i.ReportOutline) .HasForeignKey(i => i.OutlineId); modelBuilder.Entity<OutlineItem>() .HasKey(p => p.Id) .HasMany(p => p.OutlineItems) .WithOptional(c => c.ParentOutlineItem) .HasForeignKey(c => c.ParentOutlineItemId);

Esto produce la estructura correcta de la base de datos, y mis registros se ven bien. Aquí hay un ejemplo de cómo sería la tabla OutlineItems con dos elementos en un ReportOutline , si uno tenía dos elementos secundarios (cuatro en total):

Id Name ReportOutlineId ParentOutlineItemId 1 Introduction 1 NULL 2 Pets 1 NULL 3 Cats 1 2 4 Dogs 1 2

Sin embargo, cuando el ReportOutline se carga a través del DbContext , dado que ReportOutlineId coincidía con el Id del esquema, ReportOutline.OutlineItems está ReportOutline.OutlineItems con los cuatro elementos. Esto da como resultado que los subelementos aparezcan tanto en los elementos principales como en el propio contorno principal:

Title: My Report Author: valverij I. Introduction (Id: 1) II. Pets (Id: 2) A. Cats (Id: 3) B. Dogs (Id: 4) III. Cats (Id: 3) <--- Duplicated IV. Dogs (Id: 4) <--- Duplicated

Ahora, si estuviera usando NHibernate con FluentNhibernate, podría especificar una condición where en la asignación de entidad, de modo que ReportOutline.OutlineItems solo ReportOutline.OutlineItems elementos principales:

// in ReportOutlineMap HasMany(x => x.OutlineItems).Where("ParentOutlineItemId IS NULL");

Sin eso, tendría que acordarme de acceder solo a los objetos de ReportOutline través de una consulta escrita previamente que trata explícitamente con la colección OutlineItem .


Puede agregar una propiedad "RootOutlineItems" a la clase ReportOutline que filtra por usted, luego, llame cuando desee solo el 1er nivel:

public class ReportOutline { public long Id { get; set; } public string Title { get; set; } public string Author { get; set; } public virtual ICollection<OutlineItem> OutlineItems { get; set; } public ICollection<OutlineItem> RootOutlineItems { get { return OutlineItems.Where(p=> p.ParentOutlineItem == null); } } }

Otra opción sería hacer que el ReportOutline de OutlineItem se pueda anular, y solo establecer la propiedad ReportOutline o ParentOutlineItem, pero eso es un poco dudoso, además de que tendría que navegar por el árbol si alguna vez quiere todos los elementos.