Я думаю, вы можете принять это под неправильным углом.В NHibernate довольно необычно явно отображать отношение «многие ко многим» как объект модели.См. Ниже предложение об изменениях.
Учитывая объект домена MyMember
и его переопределенное отображение:
public class MyMember : DomainObjectBase
{
public virtual string Name { get; set; }
public virtual IList<MyMember> Follows { get; set; }
}
public class MemberOverride : IAutoMappingOverride<MyMember>
{
public void Override(AutoMapping mapping)
{
mapping.HasManyToMany<MyMember> (x => x.Follows)
.Table("FollowMap")
.ParentKeyColumn("FollowerID")
.ChildKeyColumn("FollowedID")
.Cascade.SaveUpdate(); ;
}
}
Следующий тестовый этап:
[Test]
public void WhoFollowsWho()
{
var a = new MyMember {Name = "A"};
var b = new MyMember {Name = "B"};
var c = new MyMember {Name = "C"};
var d = new MyMember {Name = "D"};
var e = new MyMember {Name = "E"};
a.Follows = new List<MyMember> { b, c, d, e };
d.Follows = new List<MyMember> { a, c, e };
using (var t = Session.BeginTransaction())
{
Session.Save(a);
Session.Save(b);
Session.Save(c);
Session.Save(d);
Session.Save(e);
t.Commit();
}
using (var t = Session.BeginTransaction())
{
DetachedCriteria followersOfC = DetachedCriteria.For<MyMember>();
followersOfC.CreateCriteria("Follows")
.Add(Expression.Eq("Id", c.Id))
.SetProjection(Projections.Property("Name"));
var results = followersOfC.GetExecutableCriteria(Session).List();
t.Commit();
CollectionAssert.AreEquivalent(new[]{"A", "D"}, results);
}
using (var t = Session.BeginTransaction())
{
DetachedCriteria followedByA = DetachedCriteria.For<MyMember>();
followedByA.CreateAlias("Follows", "f")
.Add(Expression.Eq("Id", a.Id))
.SetProjection(Projections.Property("f.Name"));
var results = followedByA.GetExecutableCriteria(Session).List();
t.Commit();
CollectionAssert.AreEquivalent(new[]{"B", "C", "D", "E"}, results);
}
}
ИПроизведенный SQL полагается, как и ожидалось, на внутренние объединения:
NHibernate:
SELECT this_.Name as y0_ FROM "MyMember" this_
inner join FollowMap follows3_ on this_.Id=follows3_.FollowerID
inner join "MyMember" mymember1_ on follows3_.FollowedID=mymember1_.Id
WHERE mymember1_.Id = @p0
NHibernate:
SELECT f1_.Name as y0_ FROM "MyMember" this_
inner join FollowMap follows3_ on this_.Id=follows3_.FollowerID
inner join "MyMember" f1_ on follows3_.FollowedID=f1_.Id
WHERE this_.Id = @p0
Примечание: Если вместо извлечения только свойства «Имя» каждого MyMember, вы получите полныйВ экземплярах MyMember оператор SQL сохраняет ту же форму.К предложению SELECT добавляются только дополнительные проекции.Однако вам придется исправить тест, чтобы он снова прошел; -)
Примечание 2: При условии, что вы готовы иметь дело с отношением "многие ко многим", которое имеет местособственные свойства, эта запись от Кайл Бэйли и эта одна из блога Nhibernate могут оказать некоторую помощь по этому вопросу.
Примечание 3: Я попробовал: -)
Учитывая объекты домена MySecondMember
и MyFollowMap
и их переопределенное отображение:
public class MySecondMember : DomainObjectBase
{
public virtual string Name { get; set; }
public virtual IList<MyFollowMap> Follows { get; set; }
}
public class MyFollowMap : DomainObjectBase
{
public virtual MySecondMember Who { get; set; }
public virtual DateTime StartedToFollowOn { get; set; }
}
public class MemberSecondOverride : IAutoMappingOverride<MySecondMember>
{
public void Override(AutoMapping mapping)
{
mapping.HasMany(x => x.Follows);
}
}
следующий тестовый проход:
[Test]
public void WhoFollowsWho2()
{
var a = new MySecondMember { Name = "A" };
var b = new MySecondMember { Name = "B" };
var c = new MySecondMember { Name = "C" };
var d = new MySecondMember { Name = "D" };
var e = new MySecondMember { Name = "E" };
var bfm = new MyFollowMap { Who = b, StartedToFollowOn = DateTime.UtcNow };
var cfm = new MyFollowMap { Who = c, StartedToFollowOn = DateTime.UtcNow };
var dfm = new MyFollowMap { Who = d, StartedToFollowOn = DateTime.UtcNow };
var efm = new MyFollowMap { Who = e, StartedToFollowOn = DateTime.UtcNow };
a.Follows = new List { bfm, cfm, dfm, efm };
var afm = new MyFollowMap { Who = a, StartedToFollowOn = DateTime.UtcNow };
cfm = new MyFollowMap { Who = c, StartedToFollowOn = DateTime.UtcNow };
efm = new MyFollowMap { Who = e, StartedToFollowOn = DateTime.UtcNow };
d.Follows = new List { afm, cfm, efm };
using (var t = Session.BeginTransaction())
{
Session.Save(a);
Session.Save(b);
Session.Save(c);
Session.Save(d);
Session.Save(e);
t.Commit();
}
using (var t = Session.BeginTransaction())
{
DetachedCriteria followersOfC = DetachedCriteria.For<MySecondMember>();
followersOfC.CreateAlias("Follows", "f")
.CreateAlias("f.Who", "w")
.Add(Expression.Eq("w.Id", c.Id))
.SetProjection(Projections.Property("Name"));
var results = followersOfC.GetExecutableCriteria(Session).List();
t.Commit();
CollectionAssert.AreEquivalent(new[] { "A", "D" }, results);
}
using (var t = Session.BeginTransaction())
{
DetachedCriteria followedByA = DetachedCriteria.For<MySecondMember>();
followedByA
.CreateAlias("Follows", "f")
.CreateAlias("f.Who", "w")
.Add(Expression.Eq("Id", a.Id))
.SetProjection(Projections.Property("w.Name"));
var results = followedByA.GetExecutableCriteria(Session).List();
t.Commit();
CollectionAssert.AreEquivalent(new[] { "B", "C", "D", "E" }, results);
}
}
И полученный SQL полагается, как и ожидалось, на внутренние объединения:
NHibernate:
SELECT this_.Name as y0_ FROM "MySecondMember" this_
inner join "MyFollowMap" f1_ on this_.Id=f1_.MySecondMember_id
inner join "MySecondMember" w2_ on f1_.Who_id=w2_.Id
WHERE w2_.Id = @p0;
NHibernate:
SELECT w2_.Name as y0_ FROM "MySecondMember" this_
inner join "MyFollowMap" f1_ on this_.Id=f1_.MySecondMember_id
inner join "MySecondMember" w2_ on f1_.Who_id=w2_.Id
WHERE this_.Id = @p0