【问题标题】:HashSet vs HashedSet (Iesi): strange behaviorHashSet vs HashedSet(Iesi):奇怪的行为
【发布时间】:2013-01-08 11:12:30
【问题描述】:

今天我在我的域模型上测试了一些东西,我意识到这种行为不是我所期望的。

我试图通过创建一个简单的Customers-Orders 模型来隔离问题。

这是我的映射。

客户:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class xmlns="urn:nhibernate-mapping-2.2" name="NHVariousTests.Domain.Customer, NHVariousTests" table="Customers">
    <id name="Code" type="System.Guid">
        <column name="CustomerCode" />
        <generator class="guid.comb" />
    </id>
    <version name="Version" type="System.Int32" unsaved-value="0" access="backfield"">
        <column name="Version" not-null="true" />
    </version>
    <property name="Description" type="AnsiString">
          <column name="Description" not-null="false" />
    </property>   
    <set name="Orders" access="field.pascalcase-underscore" cascade="all-delete-orphan" inverse="true" lazy="true">
        <key column="CustomerCode" />
        <one-to-many class="NHVariousTests.Domain.Order, NHVariousTests" />
    </set>
  </class>
</hibernate-mapping>

订单:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class xmlns="urn:nhibernate-mapping-2.2" name="NHVariousTests.Domain.Order, NHVariousTests" table="Orders">
    <id name="Code" type="System.Guid">
        <column name="OrderCode" />
        <generator class="guid.comb" />
    </id>
    <version name="Version" type="System.Int32" unsaved-value="0" access="backfield">
        <column name="Version" not-null="true" />
    </version>
    <property name="Description" type="AnsiString">
        <column name="Description" not-null="false" />
    </property>   
    <many-to-one class="NHVariousTests.Domain.Customer, NHVariousTests" name="Customer">
        <column name="CustomerCode" not-null="true" />
    </many-to-one>
  </class>
</hibernate-mapping>

我的Order类很简单:

public class Order : EntityGuid
{
    public Order()
    {
    }

    public virtual string Description { get; set; }

    public virtual Customer Customer { get; set; }
}

这是我的Customer 课程:

public class Customer : EntityGuid
{
    public Customer()
    {
        this._Orders = new HashSet<Order>();
    }

    public virtual string Description { get; set; }

    #region Orders

    private readonly ICollection<Order> _Orders = null;

    public virtual ReadOnlyCollection<Order> Orders
    {
        get { return (new List<Order>(_Orders).AsReadOnly()); }
    }

    public virtual bool AddOrder(Order order)
    {
        if ((order != null) && (!this._Orders.Contains(order)))
        {
            order.Customer = this;
            this._Orders.Add(order);
            return (true);
        }
        return (false);
    }

    public virtual bool RemoveOrder(Order order)
    {
        if ((order != null) && (this._Orders.Contains(order)))
        {
            this._Orders.Remove(order);
            order.Customer = null;
            return (true);
        }
        return (false);
    }

    #endregion
}

在第一个示例中,我使用的是私有 ICollection&lt;Order&gt;,它被创建为 HashSet&lt;Order&gt;

如果我运行这段代码:

using (var session = sessionFactory.OpenSession())
{
    using (var tx = session.BeginTransaction())
    {
        var customer = new Domain.Customer() { Description = "ACME Ltd" };

        var order = new Domain.Order() { Description = "Coffee" };
        customer.AddOrder(order);

        order = new Domain.Order() { Description = "Milk" };
        customer.AddOrder(order);

        session.Save(customer);

        tx.Commit();
    }
}

我可以看到客户的INSERT 和订单的两个INSERT,但我也有一个客户的UPDATE

如果我将我的 Customer 类切换到 Iesi 集合:

public class Customer : EntityGuid
{
    public Customer()
    {
        this._Orders = new Iesi.Collections.Generic.HashedSet<Order>();
    }

    public virtual string Description { get; set; }

    #region Orders

    private readonly ICollection<Order> _Orders = null;

    public virtual ReadOnlyCollection<Order> Orders
    {
        get { return (new List<Order>(_Orders).AsReadOnly()); }
    }

    public virtual bool AddOrder(Order order)
    {
        if ((order != null) && (!this._Orders.Contains(order)))
        {
            order.Customer = this;
            this._Orders.Add(order);
            return (true);
        }
        return (false);
    }

    public virtual bool RemoveOrder(Order order)
    {
        if ((order != null) && (this._Orders.Contains(order)))
        {
            this._Orders.Remove(order);
            order.Customer = null;
            return (true);
        }
        return (false);
    }

    #endregion
}

我得到了预期的行为:

这是我的EntityGuid 班级:

public abstract class EntityGuid : EntityWithTypedId<Guid>, IAuditedEntity
{
    public EntityGuid()
    {
        this.CreatedDate = DateTime.Now;
        this.UpdatedDate = DateTime.Now;
        this.CreatedBy = "";
        this.UpdatedBy = "";
    }

    public virtual DateTime CreatedDate { get; set; }
    public virtual string CreatedBy { get; set; }

    public virtual DateTime UpdatedDate { get; set; }
    public virtual string UpdatedBy { get; set; }

    public virtual int Version { get; private set; }

    public virtual bool IsTransient()
    {
        return (EntityWithTypedId<Guid>.Equals(this.Code, default(Guid)));
    }

    public virtual bool IsTransient(EntityWithTypedId<Guid> obj)
    {
        return obj != null && Equals(obj.Code, default(Guid));
    }

}

有没有人可以帮助我尝试了解正在发生的事情?

问候。

如果有人真的有兴趣看看代码。我已经清理了所有东西并使其尽可能简单。可以下载here(NH_CollectionProblems)。

我正在使用 NHibernate 3.3.2.4000

【问题讨论】:

  • 在客户映射中设置 dynamic-update="true" 以便您可以看到正在更新的内容。我也会尝试将 Orders 返回类型更改为IEnumerable&lt;Order&gt;
  • 谢谢杰米。似乎唯一正在更新的是版本。如果我使用 IEnumerable 会发生同样的事情。
  • 尝试删除不必要的集合初始化程序。即不设置_Orders = null。版本是如何分配的?
  • Jamie:我添加了抽象类 EntityGuid 并删除了初始化程序,因此我的成员看起来像这样:private ICollection&lt;Order&gt; _Orders = new HashSet&lt;Order&gt;(); 但仍然是同样的问题。
  • Jamie:如果我删除它,肯定与版本有关,因为一切正常。

标签: c# nhibernate readonly-collection iesi-collections


【解决方案1】:

您期望的行为是错误的,您应该期望在版本化实体上修改集合会更新版本。 the documentation 中描述了这种行为,用于映射一个集合,该集合还描述了如何禁用它:

optimistic-lock(可选 - 默认为 true):更改集合状态的物种会导致拥有实体的版本增加。 (对于一对多关联,禁用此设置通常是合理的。)

我确实拉下项目并验证更改此设置会切换正在发布的更新:false = 无更新,true(默认)= 更新。但是,我无法使用 Iesi HashedSet 获得预期的行为。我认为这是一个错误,但我现在没有更多时间来处理它。

【讨论】:

  • 非常感谢您的帮助,杰米。非常感谢。
【解决方案2】:

要么...

【讨论】:

    猜你喜欢
    • 2012-03-16
    • 1970-01-01
    • 2012-06-01
    • 1970-01-01
    • 2011-07-27
    • 2019-04-15
    • 1970-01-01
    • 2015-10-15
    相关资源
    最近更新 更多