C# 使用NHibernate时避免setter属性中的逻辑

C# 使用NHibernate时避免setter属性中的逻辑,c#,nhibernate,lazy-loading,eager-loading,C#,Nhibernate,Lazy Loading,Eager Loading,我有一个这样的设计: public class Employee { //... } public class Company { private IList<Employee> _employees; public IList<Employee> Employees { get { return _employees; } set { if (_employees == value) {

我有一个这样的设计:

public class Employee {
    //...
}

public class Company {
    private IList<Employee> _employees;

    public IList<Employee> Employees {
        get { return _employees; }
        set {
            if (_employees == value) {
                return;
            }

            _employees = value;

            //Some logic here. Eg:
            //Raise PropertyChanged
            //Iterate over the new values to suscribe to some events, etc.
        }
    }
}
公共类员工{
//...
}
公营公司{
私营IList_员工;
公务员{
获取{return\u employees;}
设置{
如果(_employees==值){
返回;
}
_员工=价值;
//这里有一些逻辑。例如:
//增加财产改变
//迭代新值以支持某些事件等。
}
}
}
当我尝试做以下事情时:

var employees = session.Query<Company>().Fetch(x => x.Employees).ToList();
var employees=session.Query().Fetch(x=>x.employees.ToList();
它抛出一个
懒散初始化异常

非法访问加载集合

我发现的唯一解决方法是将逻辑移到一个方法,将此方法公开(和虚拟),并为
employees
中的每个实例调用该方法,但我不喜欢这样,因为我将从存储库中调用该方法


有什么想法吗?

您将从数据库获取数据与控制逻辑混合在一起。我建议将数据提取到简单的值对象中。然后将其转换为公司和员工逻辑类。这样,您就可以根据数据将数据实体与功能分离。

您将从数据库获取数据与控制逻辑混合在一起。我建议将数据提取到简单的值对象中。然后将其转换为公司和员工逻辑类。通过这种方式,您可以根据数据将数据实体与功能分离。

在Nhibernate中,您的集合类不应暴露于外部世界。您的典型域如下所示

public class Company
{
    public virtual String Id { get; set; }

    public virtual ICollection<Employee> Employees { get; protected set; }

    public Company()
    {
        Employees = new List<Employee>();
    }

    public void AddEmployee(Employee employee)
    {
        if (Employees.Contains(employee))
            return;

        Employees.Add(employee);
        employee.Company = this;
    }

    public void RemoveEmployee(Employee employee)
    {
        if (!Employees.Contains(employee))
            return;

        Employees.Remove(employee);
    }
}

public class Employee
{
    public virtual String Id { get; set; }
    public virtual String FullName { get; set; }
    public virtual Company Company { get; set; }
}
上市公司
{
公共虚拟字符串Id{get;set;}
公共虚拟ICollection雇员{get;protected set;}
上市公司()
{
雇员=新名单();
}
公共无效添加员工(员工)
{
if(Employees.Contains(Employees))
返回;
Employees.Add(Employees);
employee.Company=this;
}
公共作废删除员工(员工)
{
如果(!employee.Contains(employee))
返回;
雇员。移除(雇员);
}
}
公营雇员
{
公共虚拟字符串Id{get;set;}
公共虚拟字符串全名{get;set;}
公共虚拟公司公司{get;set;}
}
我同意第一个响应者对用户查看模型和INPC的说法,但是如果你想直接绑定到你的域对象,你可以直接将INPC注入到你的域对象中


请在Nhibernate中查看来自Ayende的原稿和来自Ricardo的更新,您的收藏类不应暴露于外部世界。您的典型域如下所示

public class Company
{
    public virtual String Id { get; set; }

    public virtual ICollection<Employee> Employees { get; protected set; }

    public Company()
    {
        Employees = new List<Employee>();
    }

    public void AddEmployee(Employee employee)
    {
        if (Employees.Contains(employee))
            return;

        Employees.Add(employee);
        employee.Company = this;
    }

    public void RemoveEmployee(Employee employee)
    {
        if (!Employees.Contains(employee))
            return;

        Employees.Remove(employee);
    }
}

public class Employee
{
    public virtual String Id { get; set; }
    public virtual String FullName { get; set; }
    public virtual Company Company { get; set; }
}
上市公司
{
公共虚拟字符串Id{get;set;}
公共虚拟ICollection雇员{get;protected set;}
上市公司()
{
雇员=新名单();
}
公共无效添加员工(员工)
{
if(Employees.Contains(Employees))
返回;
Employees.Add(Employees);
employee.Company=this;
}
公共作废删除员工(员工)
{
如果(!employee.Contains(employee))
返回;
雇员。移除(雇员);
}
}
公营雇员
{
公共虚拟字符串Id{get;set;}
公共虚拟字符串全名{get;set;}
公共虚拟公司公司{get;set;}
}
我同意第一个响应者对用户查看模型和INPC的说法,但是如果你想直接绑定到你的域对象,你可以直接将INPC注入到你的域对象中


请参阅Ayende的原始版本和Ricardo的更新版本。我猜您在映射中使用了“属性”作为集合访问器,如果是这样,那么您描述的行为就是代码试图修改集合时所期望的行为

如果希望在域模型中使用该模式,则应将集合访问器更改为“字段”(使用适当的命名策略),以便通知NHibernate设置支持字段“\u employees”,而不是属性“employees”


这将不会触发您尝试访问集合的代码。

我猜您正在映射中使用“属性”作为集合访问器,如果是这样,那么您描述的行为是您的代码尝试修改集合时预期的行为

如果希望在域模型中使用该模式,则应将集合访问器更改为“字段”(使用适当的命名策略),以便通知NHibernate设置支持字段“\u employees”,而不是属性“employees”


这将不会触发您尝试访问集合的代码。

我考虑过这一点,但我应该在什么时候执行该逻辑?我在setter中设置了它,以确保当新员工被设置时,我会执行一些必需的操作。否则我怎么知道新员工被分配了呢?在setter中有这样的逻辑是正确的。更改访问器可以消除初始化问题,但在初始化后仍可以触发代码。关键的概念是,您不应该在初始化时需要该代码,因为在持久化之前,必须将持久化对象视为处于有效状态,而NHibernate将仅重建该状态。我想我不理解您的意思。如果我设置了一个自定义访问(例如带有下划线前缀的LowerCaseField),它就不会调用我的属性的setter(无论是在初始化之前还是之后),因此我的逻辑永远不会执行。你是说它应该在正确初始化setter属性后调用它吗?我考虑过这个问题,但是什么时候我应该执行这个逻辑呢?我在setter中设置了它,以确保当新员工被设置时,我会执行一些必需的操作。否则怎么办