c# - 在 Entity Framework 6 中为子集合的映射添加条件,类似于 NHibernate 的 "where"

标签 c# entity-framework nhibernate entity-framework-6

在 NHibernate 中,有一个 where 映射允许您在属性映射上指定一个条件,该条件会影响它从数据库中提取的方式。例如,如果我想实现软删除并从集合中排除所有已删除的项目,我可以这样映射它:

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>

Entity Framework 6 中有类似的东西吗?

我找到的最接近的是一个名为 EntityFramework.Filters 的库,它允许您为属性添加全局过滤器,但当该属性是一个集合时它似乎不起作用。


为了更好地说明为什么需要这样的映射,假设我有一个类,其中包含具有递归子实体关系的对象集合(即,相同类型的对象集合)。它们遵循以下基本结构:

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; }
}

这些是用 EF fluent API 映射的,如下所示:

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);

这产生了正确的数据库结构,我的记录看起来很好。下面是 OutlineItems 表在 ReportOutline 上有两个项目的示例,如果一个表有两个子项目(总共四个):

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

ReportOutline 通过 DbContext 加载时,但是,由于 ReportOutlineId 与大纲的 Id 匹配, ReportOutline.OutlineItems 正在填充所有四个项目。这导致子项出现在父项和主大纲本身的下方:

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

现在,如果我将 NHibernate 与 FluentNhibernate 一起使用,我可以在实体映射上指定一个 where 条件,这样 ReportOutline.OutlineItems 只有 拉取父项:

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

否则,我将不得不记住通过显式处理OutlineItem 集合的预写查询访问ReportOutline 对象.

最佳答案

您可以将“RootOutlineItems”属性添加到为您过滤的 ReportOutline 类,然后在您只需要第一级时调用它:

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);
        }
    }
}

另一种选择是使 OutlineItem 的 ReportOutline 可为空,并且只设置 ReportOutline 或 ParentOutlineItem 属性,但这有点不确定,而且如果您需要导航树永远想要所有的元素。

关于c# - 在 Entity Framework 6 中为子集合的映射添加条件,类似于 NHibernate 的 "where",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27324004/

相关文章:

c# - 通过 jquery 获取 updatepanel 内的复选框单击

C# .NET 对象处置

asp.net - 如何在代码优先迁移中强制删除并重新创建选定的表?

c# - 在使用 Fluent NHibernate 映射时对接口(interface)进行编程

c# - 当通过 WCF 发送对象时,如何处理 LINQ to SQL DataContext 中的关系成员?

c# - 在 Entity Framework 4.1 (POCO) 中添加具有预定义 PK 值的记录

c# - IQueryable 到底是什么意思?

c# - Entity Framework 核心 : The property expression 'xx' is not valid. 表达式应表示属性访问: 't => t.MyProperty'

database - Hibernate,将多个列分配为主键

c# - NHibernate Aurora (MySQL) 中键 'XXX' 的重复条目 'PRIMARY'