在NHibernate中,有一个where
映射,允许您在属性映射上指定一个条件,该条件会影响它从数据库中的提取方式。例如,如果我想实现软删除并从集合中排除所有删除的项目,则可以这样映射它:
流利的冬眠
// in class ParentMap : ClassMap
HasMany(x => x.Children).Where("IsDeleted = 0");
血红蛋白
<class name="Parent" table="[Parents]">
<bag cascade="all" lazy="true" name="Children" where="IsDeleted = 0">
<!-- rest of map here -->
</bag>
</class>
实体框架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");
否则,我将不得不记住只能通过预先编写的查询来访问
ReportOutline
对象,该查询明确处理OutlineItem
集合。 最佳答案
您可以将“ 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属性,但这有点麻烦,而且如果要使用所有项目,则必须导航树。