出于这个问题的目的,让我们说我有一个有多个展览的动物园。每个展览都有自己的时间表,包括一系列活动,以及负责这些活动的部门和子部门列表。
我有一个相当大的LINQ查询,我用它来获取任何附有员工的展品。将查询与IEnumerable
(session.Query<Exhibit>().AsEnumerable()
)一起使用时,它可以正常工作;但是,当我将查询切换为使用IQueryable
时,NHibernate会崩溃。
我已将查询中原始错误的初始源指向一个特定条件:
var filtered = session.Query<Exhibit>().Where(x =>
x.AnimalSchedule.Activities
.OfType<FeedActivity>()
.Any(g => g.ResponsibleDepartment.Manager == employee)
);
由于这个条件本身很长,我继续一步一步地将其分解出来:
var collection = session.Query<Exhibit>(); // works
var exhibitAnimalSchedules = collection.Select(x => x.AnimalSchedule); // works
var activities = exhibitAnimalSchedules.SelectMany(x => x.Activities); // could not execute query - Incorrect syntax near the keyword 'from'.
var feedActivities = activities.OfType<FeedActivity>(); // Could not find property nor field 'class' in class 'MyProject.Collections.ScheduleActivityCollection'
var filteredFeedActivities = feedActivities.Where(g => g.ResponsibleDepartment.Manager == employee); // Specified method is not supported.
活动上的错误也给出了NHibernate试图生成的SQL:
SELECT
FROM [dbo].[Exhibits] exhibit0_
INNER JOIN [dbo].[ExhibitAnimalSchedules] exhibitanima1_ ON exhibit0_.AnimalScheduleID = exhibitanima1_.ScheduleID
INNER JOIN [dbo].[Schedules] exhibitanima1_1_ ON exhibitanima1_.ScheduleID = exhibitanima1_1_.[ID]
WHERE exhibit0_.ZooID IS NULL
如果您注意到,NHibernate未能列出SELECT
语句中的任何列。
我是否在想这个查询错误的方法?如果这实际上是NHibernate中有一个LINQ lambdas的错误,是否有一些解决方法?
更新 - 请参阅下面的答案
看起来NHibernate在确定.SelectMany(x => x.Activities)
作为参考,以下是所涉及类的所有简化Fluent映射:
public class ExhibitMap : ClassMap<Exhibit>
{
public ExhibitMap()
{
References(p => p.AnimalSchedule).Cascade.All();
}
}
public class ScheduleMap : ClassMap<Schedule>
{
public ScheduleMap()
{
Component(x => x.Activities, m => m {
var cfg = m.HasMany<ScheduleActivity>(Reveal.Member<ScheduleActivityCollection>("_innerList")).LazyLoad();
cfg.KeyColumn("ScheduleID").Inverse();
cfg.ForeignKeyConstraintName("FK_Schedule_Activities");
cfg.Cascade.AllDeleteOrphan();
});
}
}
public class ExhibitAnimalScheduleMap : SubclassMap<ExhibitAnimalSchedule>
{
public ExhibitAnimalScheduleMap()
{
References(x => x.Exhibit).Cascade.None();
}
}
public class ScheduleActivityMap : ClassMap<ScheduleActivity>
{
public ScheduleActivityMap()
{
References(x => x.Schedule).Cascade.None().Not.LazyLoad();
}
}
public class FeedActivityMap : SubclassMap<FeedActivity>
{
public FeedActivityMap()
{
this.References(x => x.ResponsibleDepartment).Cascade.All().Not.LazyLoad();
Component(x => x.Departments, m => m {
var cfg = m.HasMany<FeedActivityDepartment>(Reveal.Member<FeedActivityDepartmentCollection>("_innerList")).LazyLoad();
cfg.KeyColumn("ScheduleID").Inverse();
cfg.ForeignKeyConstraintName("FK_Schedule_Activities");
cfg.Cascade.AllDeleteOrphan();
});
}
}
答案 0 :(得分:1)
正如@Firo指出的那样,NHibernate对我用于自定义集合的组件有一些困难。如果您查看问题中的SQL,您将看到NHibernate无法加入Activities
表和Departments
表来查找相关的负责部门。
我通过切换到LINQ查询语法并明确加入表来纠正这个问题。我还通过使用OfType
进行内联检查并使用is
进行投射,避免了as
(最常见的组件问题)的问题:
var schedules = from schedule in session.Query<Schedule>()
join activity in session.Query<ScheduleAcivity>() on schedule equals activity.Schedule
join department in session.Query<FeedActivityDepartment>() on activity equals department.FeedActivity
where (activity is FeedActivity && (activity as FeedActivity).ResponsibleDepartment.Manager == employee)
|| (department != null && department.Employee == employee)
select schedule;
var exhibits = from exhibit in session.Query<Exhibit>()
where schedules.Any(x => x == exhibit.AnimalSchedule)
select exhibit;
注意:有时NHibernate对LINQ查询中的别名名称很挑剔。如果你遵循这种模式并且仍然遇到错误,请尝试更改别名的名称(我喜欢在他们面前添加“temp” - from tempSchedule in ...
,join tempActivity in ...
等。)