简体   繁体   English

如何在不加载NHibernate中的整个集合的情况下插入项目?

[英]How to insert an item without loading the entire collection in NHibernate?

I have a class model that looks like this: 我有一个类似于以下的类模型:

public class TheSystem 
{
    public virtual Guid Id { get; protected set; }
    public virtual ICollection<User> Users { get; protected set; }
}

public class User
{
    public virtual Guid Id { get; protected set; }
    public virtual string Username { get; set; }
    ...
}

The mappings 映射

public class TheSystemMap : ClassMap<TheSystem>
{
    public TheSystemMap()
    {
        Id(x => x.Id).GeneratedBy.GuidComb();
        HasMany(x => x.Users).Cascade.AllDeleteOrphan().ExtraLazyLoad().Cache.ReadWrite().IncludeNonLazy();

        Cache.ReadOnly();
    }
}

public class UserMap : ClassMap<User>
{
    public UserMap()
    {
        Id(x => x.Id).GeneratedBy.GuidComb();
        Map(x => x.Username).Not.Nullable();
        ...

        Cache.ReadOnly();
    }
}

The problem arrives when I want to add a new user to the system. 当我想向系统添加新用户时,问题就出现了。 Because of I'm referencing the Users collection, NHibernate loads all the instances (which I don't want, because I just want to insert the single user). 由于我引用了Users集合,NHibernate加载了所有实例(我不想要,因为我只想插入单个用户)。

...
theSystem.Users.Add(new User("aUser"));
...

The ExtraLazyLoad() option is working as expected when I try to get the item's count (The code next produces to query only for the count) 当我尝试获取项目的计数时, ExtraLazyLoad()选项按预期工作(下一个代码生成只查询计数)

...
var count = theSystem.Users.Count;
...

I've also try adding .AsBag() option with the same result. 我也尝试添加.AsBag()选项,结果相同。

I'm missing something in the mapping or is a situation that can't be solved the regular ways? 我在映射中遗漏了某些东西,或者是一种无法通过常规方式解决的情况?

If you're doing a model like this, chances are you're looking to have an API surface that constrains its consumers so they can only perform valid operations. 如果您正在做这样的模型,那么您可能希望拥有一个限制其消费者的API表面,以便它们只能执行有效的操作。 When I do this, I generally enforce complete public immutability of the entities. 当我这样做时,我通常会强制实体完全公开不变。 All public operations that change state of any kind are mediated through methods or objects modelling valid business actions that can be validated and checked. 所有改变状态的公共操作都是通过建模可以验证和检查的有效业务操作的方法或对象来调解的。 Then there's an internal API that is less constrained, and direct access to the persistence mechanism is available at this level. 然后是一个内部API受限制较少,并且在此级别可以直接访问持久性机制。

In this model, collections are exposed at the public API surface as IEnumerable<T> and mapped to the underlying fields, and I add methods to the relevant controlling entities to create/add and remove child objects (provided this is a valid domain operation, of course). 在此模型中,集合在公共API表面公开为IEnumerable<T>并映射到基础字段,我将方法添加到相关控制实体以创建/添加和删除子对象(假设这是一个有效的域操作,当然)。 Something like 就像是

theSystem.AddUser(user);

and

theSystem.RemoveUser(user);

Though in point of fact my add method will most likely look like 虽然事实上我的添加方法很可能看起来像

theSystem.AddUser(email, password, confirmPassword, firstName, lastName)

since I don't allow API consumers to construct any persisted entity directly. 因为我不允许API使用者直接构造任何持久化实体。 The AddUser method constructs the user, saves it to the session, and adds it to the Users collection. AddUser方法构造用户,将其保存到会话,并将其添加到Users集合。 Or if there's a cascade (which I generally avoid), just adds it to the collection. 或者如果有级联(我通常会避免),只需将其添加到集合中即可。

(Doesn't work well with DI, of course, but then again that's not the sort of API I'm building here. If there's DI going on it happens lower down.) (当然,与DI不兼容,但是那时我不再是那种我正在构建的API。如果正在进行DI,它会发生降低。)

You could just create a new User and avoid TheSystem all together: 您可以创建一个新用户并一起避免TheSystem

User newUser = new User();
session.Save(newUser);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM