2013-02-20 2 views
2

Хотя я много раз пользовался коллективной мудростью этого сайта, это мой первый вопрос здесь.Как вернуть только один конкретный элемент из отношения hasmany

у меня есть, скажем, три класса, как так:

public class ClassA 
{ 
    public ClassA() {} 

    public virtual IList<ClassB> ClassBs { get; set; } 
} 

public class ClassB 
{ 
    public ClassB() {} 

    public virtual DateTime StartDate { get; set; } 
    public virtual DateTime? EndDate { get; set; } 
    public virtual ClassC SomeObject { get; set; } 
} 

public class ClassC 
{ 
    public ClassC() {} 

    public virtual string Name { get; set; } 
} 

Я использую NHibernate (3.3.1.4) и FluentNHibernate (1.3.0.733), и файлы отображения являются:

public Class ClassAMap : ClassMap<ClassA> 
{ 
    HasMany(x => x.ClassBs); 
} 

public Class ClassBMap : ClassMap<ClassB> 
{ 
    Map(x => x.StartDate).Not.Nullable(); 
    Map(x => x.EndDate).Nullable(); 
    References(x => x.SomeData).Not.Nullable(); 
} 

public Class ClassCMap : ClassMap<ClassC> 
{ 
    Map(x => x.Name).Not.Nullable(); 
} 

Есть также идентификаторы и версии, но я почему-то думаю, что они неактуальны.

То, что я хочу сделать, это:

select all "SomeObject"s from ClassBs of all "ClassA"s which have their "EndDate"s null and which have the most current StartDate in their group. 

Я пробовал некоторые жонглирование с QueryOver, но максимум, что я мог бы получить был IList<IList<ClassB>>, который на самом деле далеко от того, что я хочу сделать.

Редактировать: (я думаю) Следующий код выполняет задачу с Linq. Но для этого кода требуются все записи из БД. Это не может быть проблемой для ClassB с до 3-х записей или так для ClassA, но для ClassB с сотнями записей это означает, что все эти записи из БД используют только одну запись из ClassB каждого классаA в БД.

IList<ClassC> classCLs = new List<ClassC>(); 
ClassB latest = null; 
foreach (
    IList<ClassB> classBLs in 
     Session.QueryOver<ClassA>() 
      .Select(c => c.ClassBs).List<IList<ClassB>>() 
) { 
    latest = classBLs.Where(cB => cB.EndDate == null).Aggregate((curr, next) => next.StartDate > curr.StartDate ? next : curr); 
    if (latest != null && !classCLs.Contains(latest.SomeObject)) { 
     classCLs.Add(latest.SomeObject); 
    } 
} 

ответ

0

Если предположить, что CLASSA имеет свойство Id, может быть, это, с участием подзапрос, может иметь некоторую помощь:

ClassA aAlias = null; 
ClassB bAliasMax = null, bAlias = null; 

var subQuery = QueryOver.Of<ClassA>().JoinAlias(a => a.ClassBs,() => bAliasMax) 
         .Where(Restrictions.On(() => bAliasMax.EndDate).IsNotNull) 
         .Where(a=>a.Id==aAlias.Id) 
         .Select(Projections.Max(() => bAliasMax.StartDate)); 

var result = 
    _laSession.QueryOver(() => aAlias) 
       .JoinAlias(a => a.ClassBs,() => bAlias) 
       .WithSubquery.WhereProperty(() => bAlias.StartDate).Eq(subQuery) 
       .Select(Projections.Property(() => bAlias.SomeObject)) // suggested adding from question's author 
       .List<ClassC>(); // see above 

Я предполагаю, что есть более эффективные ответы, которые бы вовлекают группировки.

+0

это возвращает объект, состоящий из двух таблиц (ClassA и ClassB), соединенных вместе. Я добавил '.Select (Projections.Property (() => bAlias.SomeObject))' afer строка, начинающаяся с '.WithSubquery ...' и изменившая 'List()' на 'List ()' – mevtagezer

+0

@mevtagezer ok, не понял, что «SomeObject» относится к «SomeObject» класса ClassC и просто читает «Все объекты ClassB» ;-) – jbl

+0

Если вы отредактируете свой ответ, я пометю его как принятый. Спасибо. – mevtagezer

Смежные вопросы