如何不在 NHibernate 中加载一个特定的 属性(根本,甚至是懒惰的)?
How not load one specific property (at all, even lazy) in NHibernate?
我正在使用 Nhibernate 5.2.3 和 ASP.NET Core 2.2。我有一个实体 Cat,它有很多 Kitten。我想在加载 Cat 时设置这样的查询,根本不加载任何 Kitten。
我试过使用 'Lazy' 属性和 LINQ。
然后我尝试使用 'ICriteria' 和 'Fecth' 方法来设置 'SelectMode.Skip' 但它没有帮助。
有我对 DB
的查询
var cat = _session.CreateCriteria<Cat>()
.Add(Restrictions.Eq(nameof(Cat.Id), id))
.Fetch(SelectMode.Skip, nameof(Cat.Kittens))
.UniqueResult<GH>();
有类和它们的映射(由Nhibernate.Mapping.Attribute)
public class Cat
{
[Id(Column = "NUM_REC", Type = "Int32", Name = "Id", Generator = "identity")]
public virtual int Id { get; set; }
[Bag(Cascade = "all-delete-orphan", Inverse = true, Lazy = CollectionLazy.False)]
[Key(Column = "NUM_CAT")]
[OneToMany(ClassType = typeof(Kitten))]
public virtual IList<Kitten> Kittens { get; set; }
}
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; }
}
我想要这样制作:仅加载 'Cat' 的 'Id' 属性 并且不加载(惰性、获取、急切)Kittens 集合。
是否必须使用条件 API?
我也不太熟悉这个属性映射,但是为了让延迟加载工作,所有关联都需要 bi-directional(我记得在文档中看到过这个但找不到它) .这种关系你需要指定双方的关系,即小猫对象需要一个 public virtual Cat Parent { get; set; }
而这个 属性 将被映射 [ManyToOne(Column="NUM_CAT", Lazy="Proxy")]
.
反向实际上只对 bi-directional 关联很重要,否则无论你为 inverse
指定什么,它总是 inverse=true
因为另一个实体对父实体一无所知,所以你自动让父 Cat
对关联负责。
将 Parent
属性 添加到 Cat
对象后,如果为 Kittens
[=83= 指定了 inverse=false
,则在 Cat 对象上] 那么这意味着 Cat
负责管理并将自己归于 Kitten
。换句话说,NHibernate 在保存操作期间设置 NUM_CAT
的值。对于 inverse=true
,Cat
不会为您管理该关联,而是任何时候将 Kitten
添加到 Cat
,Parent
[= Kitten
上的 83=] 需要设置为正在将 Kitten
添加到其集合的 Cat
的父实例。
取下面的代码:
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。我通常将其映射为 Kittens 是 inverse=false
并尝试通过将袋子包装在 Enumerable 中来使 Cat
管理的关联仍然如此,因此外部用户无法将小猫直接添加到列表和设置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);
}
}
}
要获得所需的行为,请确保添加 bi-directional 关联以启动并:
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)
因为这将代理对象并避免使用数据库,除非调用 属性。如果您想做一些更复杂的事情,请忽略小猫...
我正在使用 Nhibernate 5.2.3 和 ASP.NET Core 2.2。我有一个实体 Cat,它有很多 Kitten。我想在加载 Cat 时设置这样的查询,根本不加载任何 Kitten。
我试过使用 'Lazy' 属性和 LINQ。 然后我尝试使用 'ICriteria' 和 'Fecth' 方法来设置 'SelectMode.Skip' 但它没有帮助。 有我对 DB
的查询var cat = _session.CreateCriteria<Cat>()
.Add(Restrictions.Eq(nameof(Cat.Id), id))
.Fetch(SelectMode.Skip, nameof(Cat.Kittens))
.UniqueResult<GH>();
有类和它们的映射(由Nhibernate.Mapping.Attribute)
public class Cat
{
[Id(Column = "NUM_REC", Type = "Int32", Name = "Id", Generator = "identity")]
public virtual int Id { get; set; }
[Bag(Cascade = "all-delete-orphan", Inverse = true, Lazy = CollectionLazy.False)]
[Key(Column = "NUM_CAT")]
[OneToMany(ClassType = typeof(Kitten))]
public virtual IList<Kitten> Kittens { get; set; }
}
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; }
}
我想要这样制作:仅加载 'Cat' 的 'Id' 属性 并且不加载(惰性、获取、急切)Kittens 集合。
是否必须使用条件 API?
我也不太熟悉这个属性映射,但是为了让延迟加载工作,所有关联都需要 bi-directional(我记得在文档中看到过这个但找不到它) .这种关系你需要指定双方的关系,即小猫对象需要一个 public virtual Cat Parent { get; set; }
而这个 属性 将被映射 [ManyToOne(Column="NUM_CAT", Lazy="Proxy")]
.
反向实际上只对 bi-directional 关联很重要,否则无论你为 inverse
指定什么,它总是 inverse=true
因为另一个实体对父实体一无所知,所以你自动让父 Cat
对关联负责。
将 Parent
属性 添加到 Cat
对象后,如果为 Kittens
[=83= 指定了 inverse=false
,则在 Cat 对象上] 那么这意味着 Cat
负责管理并将自己归于 Kitten
。换句话说,NHibernate 在保存操作期间设置 NUM_CAT
的值。对于 inverse=true
,Cat
不会为您管理该关联,而是任何时候将 Kitten
添加到 Cat
,Parent
[= Kitten
上的 83=] 需要设置为正在将 Kitten
添加到其集合的 Cat
的父实例。
取下面的代码:
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。我通常将其映射为 Kittens 是 inverse=false
并尝试通过将袋子包装在 Enumerable 中来使 Cat
管理的关联仍然如此,因此外部用户无法将小猫直接添加到列表和设置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);
}
}
}
要获得所需的行为,请确保添加 bi-directional 关联以启动并:
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)
因为这将代理对象并避免使用数据库,除非调用 属性。如果您想做一些更复杂的事情,请忽略小猫...