Нужно ли использовать Criteria API?
Я не слишком знаком с этим сопоставлением атрибутов, но для того, чтобы загрузка Lazy работала вообще, связь должна быть двунаправленной (я помню, что видел это в документации, но не могу ее найти). Это отношение необходимо указать для обеих сторон, т. Е. Объекту котенка требуется public virtual Cat Parent { get; set; }
, и это свойство будет отображено [ManyToOne(Column="NUM_CAT", Lazy="Proxy")]
.
Обратное действительно имеет значение только для двунаправленных ассоциаций, в противном случае, независимо от того, что вы указываете для inverse
, оно всегда будет inverse=true
, потому что другая сущность ничего не знает о родителе, и поэтому вы автоматически делаете родителя Cat
ответственный за ассоциацию.
После добавления свойства Parent
к объекту Cat
, а затем к объекту Cat, если для свойства Kittens
указано inverse=false
, это означает, что Cat
отвечает за управление и присвоение себя Kitten
. Другими словами, NHibernate устанавливает значение NUM_CAT
во время операций сохранения. С inverse=true
, Cat
не будет управлять этой ассоциацией для вас, и вместо этого, каждый раз, когда Kitten
добавляется к Cat
, свойство Parent
в Kitten
должно быть установлено для родительского элемента экземпляр Cat
, который добавляет Kitten
в свою коллекцию.
Возьмите следующий код:
var mom = new Cat();
var child1 = new Kitten();
var child2 = new Kitten();
mom.Kittens.Add(child1);
mom.Kittens.Add(child2);
session.Save(mom);
session.Save(child1);
session.Save(child2);
С inverse=false
:
insert into Cat (NUM_REC) values (1)
insert into Kitten (NUM_REC, NUM_CAT, NAME) values (1, 1, 'Foo')
insert into Kitten (NUM_REC, NUM_CAT, NAME) values (2, 1, 'Foo')
С inverse=true
:
insert into Cat (NUM_REC) values (1)
--error!, NHibernate has no value for Cat/NUM_CAT
Так что, если мы установим inverse=false
, нам нужно немного изменить код:
var mom = new Cat();
var child1 = new Kitten();
var child2 = new Kitten();
mom.Kittens.Add(child1); child1.Parent = mom;
mom.Kittens.Add(child2); child2.Parent = mom;
session.Save(mom);
session.Save(child1);
session.Save(child2);
И мы получим желаемый SQL. Я обычно сопоставляю это с котятами, являющимися inverse=false
, и пытаюсь заставить сотрудника под управлением Cat
все еще делать это, оборачивая сумку в Enumerable, чтобы внешние пользователи не могли добавлять котят непосредственно в список и устанавливать One-to-Many
access
как field.camelCase
. Подробное определение свойства можно найти в 5.1.10
public class Cat {
private IList<Kitten> kittens;
public virtual IEnumerable Kittens => kittens;
public virtual void Add(Kitten kitten){
if (kitten != null){
kitten.Cat = this;
this.kittens.Add(kitten);
}
}
}
Чтобы получить желаемое поведение, добавьте двунаправленную ассоциацию для запуска и:
public class Cat {
[Bag(Cascade="all-delete-orphan", Inverse=true, Lazy=True, Fetch=Select)]
[Key(Column="NUM_CAT", NotNull="true")]
[OneToMany(ClassType = typeof(Kitten))]
public virtual IEnumerable Kittens => kittens;
}
Указание Fetch=Join
переопределяет Lazy=true
. На тебе котенок:
public class Kitten {
[Id(Column="NUM_REC", Type="Int32", Name="Id", Generator="identity")]
public virtual int Id { get; set; }
[Property(Column="NAME")]
public virtual string Name { get; set; }
[ManyToOne(Column="NUM_CAT", Lazy="Proxy")]
public virtual Cat Parent {get;set;}
}
Теперь у вас должен быть доступ к запросам ..., при выборе объекта по Id просто используйте session.Get(id)
, если вам нужен только Id, и ничего больше не используйте session.Load(id)
, так как это проксирует объект и избегает базы данных, если только свойство вызывается. Если вы хотите сделать что-то более сложное, просто оставьте котенка ...