【发布时间】: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<Order>,它被创建为 HashSet<Order>。
如果我运行这段代码:
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<Order>。 -
谢谢杰米。似乎唯一正在更新的是版本。如果我使用 IEnumerable
会发生同样的事情。 -
尝试删除不必要的集合初始化程序。即不设置_Orders = null。版本是如何分配的?
-
Jamie:我添加了抽象类 EntityGuid 并删除了初始化程序,因此我的成员看起来像这样:
private ICollection<Order> _Orders = new HashSet<Order>();但仍然是同样的问题。 -
Jamie:如果我删除它,肯定与版本有关,因为一切正常。
标签: c# nhibernate readonly-collection iesi-collections