我正在尝试创建一个显示事件依赖关系的测试应用程序:即生成的依赖关系图(而不仅仅是树图)。类似于:
public class Event() {
public virtual int Id {get;set;}
public virtual IList<Event> Dependencies {get;set;}
}
另一个要求是我能够在两个方向上遍历图:给定任何一个事件,我都可以使用Nhibernate访问它的依赖关系及其先决条件。
许多事件可以依赖于一个事件的发生。。。而且任何给定的事件都可以取决于许多其他事件。模型应该是什么样子(或者这需要多个模型)?如何使用Fluent NHibernate进行映射?是否有配置/映射可以防止循环引用?
我们做了类似的事情,它的映射方式是依赖事件应该有一个映射到父事件的列。这将创建映射有效所需的必要父/子关系,并防止某种循环引用。我们通过代码映射切换到了NH3.2,所以我的流利可能有点粗制滥造,但我的最佳猜测是:
public class EventMap : ClassMap<Event>
{
public EventMap()
{
//the normal ID and property stuff
References(x => x.ParentEvent).Column("ParentEventId");
HasMany(x => x.Dependencies).KeyColumn("ParentEventId");
}
}
编辑:
抱歉-没看到你想要一个HasManyToMany。这可能看起来像:
public class EventMap : ClassMap<Event>
{
public EventMap()
{
//the normal ID and property stuff
HasManyToMany(x => x.Dependencies).Table("EventDependentEvent").AsBag();
}
}
这应该映射出您需要的链接表。您需要自己防范某种程度的"循环性"——也就是说,在您的业务逻辑中,确保您不能创建循环或某种大规模的对象图依赖性问题。
我最终得到的解决方案(到目前为止)。。。
模型中:
public virtual IList<Event> Dependencies{ get; set; }
public virtual IList<Event> Prerequisites{ get; set; }
在映射中:
HasManyToMany(x => x.Dependencies)
.Table("Dependencies")
.ChildKeyColumn("Dependent");
HasManyToMany(x => x.Prerequisites)
.Table("Prerequisites")
.ChildKeyColumn("Prerequisite");
我通过从中查找错误来防止循环引用
private bool IsPrerequisiteEvent(Event dependent, Event prereq)
{
bool isPrereq = false;
if (prereq == null)
isPrereq = false;
else if (dependent.Id == prereq.Id)
isPrereq = true;
else
{
int i = 0;
while (!isPrereq && i < dependent.PrerequisiteEvents.Count)
{
isPrereq |= IsPrerequisiteEvent(dependent.PrerequisiteEvents[i], prereq);
i++;
}
}
return isPrereq;
}
private bool IsDependentEvent(Event prereq, Event dependent)
{
bool isDependent = false;
if (prereq == null)
isDependent = false;
else if (dependent.Id == prereq.Id)
isDependent = true;
else
{
int i = 0;
while (!isDependent && i < dependent.DependentEvents.Count)
{
isDependent |= IsDependentEvent(prereq, dependent.DependentEvents[i]);
i++;
}
}
return isDependent;
}
这种方法有一些折衷:数据库是非规范化的,但我不必创建一个新的依赖对象,并为每个票证填充一个依赖/prereq票证列表,然后进行检查。现在用这种方式编码似乎更容易。欢迎提出建议!