This is a slightly complicated issue, so there may be a lot of code with this post. I'll try to keep it as simple as possible. When I persist my object, get the following exception:
Code:
NHibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: Com.WildTangent.ProductCatalog.Data.RuleGroupSlot at NHibernate.Impl.SessionImpl.ThrowTransientObjectException(Object obj) at NHibernate.Impl.SessionImpl.GetEntityIdentifierIfNotUnsaved(Object obj) at NHibernate.Type.EntityType.GetIdentifier(Object value, ISessionImplementor session) at NHibernate.Type.ManyToOneType.NullSafeSet(IDbCommand cmd, Object value, Int32 index, ISessionImplementor session) at NHibernate.Collection.AbstractCollectionPersister.WriteElement(IDbCommand st, Object elt, Boolean writeOrder, ISessionImplementor session) at NHibernate.Collection.Map.WriteTo(IDbCommand st, ICollectionPersister persister, Object entry, Int32 i, Boolean writeOrder) at NHibernate.Collection.AbstractCollectionPersister.Recreate(PersistentCollection collection, Object id, ISessionImplementor session) at NHibernate.Impl.ScheduledCollectionRecreate.Execute() at NHibernate.Impl.SessionImpl.Execute(IExecutable executable) at NHibernate.Impl.SessionImpl.ExecuteAll(IList list) at NHibernate.Impl.SessionImpl.Execute() at NHibernate.Impl.SessionImpl.Flush() at NHibernate.Transaction.AdoTransaction.Commit() at Com.WildTangent.NHibernateUtil.Persist.GenericNHibernateDAO`1.Persist(TemplateClass entity)
Here's the block of code that causes the error.
Code:
protected void SaveChanges(string catalogDescription)
{
if (!StringUtil.IsBlank(catalogDescription)) {
RuleGroupDAO ruleGroupDAO = new RuleGroupDAO();
SlotDAO slotDAO = new SlotDAO();
ProductDAO productDAO = new ProductDAO();
RuleGroup ruleGroup = ruleGroupDAO.GetByDescription(catalogDescription);
List<string> slotKeys = ProductSlotManagerMain.SlotKeys;
// add / update all slots
foreach (string slotKey in slotKeys) {
Slot slot = slotDAO.GetByKey(slotKey);
List<Product> productList = productDAO.GetProductsFromList(ProductSlotManagerMain.GetProductListBySlotKey(slotKey));
if (ruleGroup.RuleGroupSlots.Contains(slot)) {
RuleGroupSlot ruleGroupSlot = (RuleGroupSlot)ruleGroup.RuleGroupSlots[slot];
List<Product> existingProductList = ruleGroupSlot.GetOrderedProducts().Products;
if (!CatalogUtil.ProductListsAreEqualByOrder(productList, existingProductList)) {
ruleGroupSlot.OrderedProducts = productList;
ruleGroup.RuleGroupSlots[slot] = ruleGroupSlot;
}
} else {
if (productList.Count > 0) {
//********* fails when executing this code path
RuleGroupSlot ruleGroupSlot = new RuleGroupSlot();
ruleGroupSlot.OrderedProducts = productList;
ruleGroupSlot.Slot = slot;
ruleGroupSlot.RuleGroup = ruleGroup;
ruleGroup.RuleGroupSlots.Add(slot, ruleGroupSlot);
}
}
}
ruleGroupDAO.Persist(ruleGroup);
//********* fails on persist (Save)
}
}
hibernate mappings:
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0"
namespace="Com.WildTangent.ProductCatalog.Data"
assembly="ProductCatalog">
<class name="RuleGroup" table="t_RuleGroup" lazy="true">
<cache usage="read-write" />
<id name="Id" column="RuleGroupId" type="int">
<generator class="native" />
</id>
... irrelevant stuff ...
<map name="RuleGroupSlots" table="t_RuleGroupSlot" batch-size="50" lazy="true" cascade="none">
<key column="RuleGroupId" />
<index-many-to-many class="Slot" column="SlotId" />
<one-to-many class="RuleGroupSlot" />
</map>
</class>
</hibernate-mapping>
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0"
namespace="Com.WildTangent.ProductCatalog.Data"
assembly="ProductCatalog">
<class name="RuleGroupSlot" table="t_RuleGroupSlot" lazy="true">
<cache usage="read-write" />
<id name="Id" column="RuleGroupSlotId" type="int">
<generator class="native" />
</id>
<list name="OrderedProducts" table="t_ProductSlotOrder">
<key column="RuleGroupSlotId" />
<index column="`Order`" />
<many-to-many column="ProductId" class="Product" />
</list>
</class>
</hibernate-mapping>
Persistent objects:
Code:
public class RuleGroup
{
public virtual int Id
{
get { return _id; }
set { _id = value; }
}
public virtual IDictionary RuleGroupSlots
{
get { return _ruleGroupSlots; }
set { _ruleGroupSlots = value; }
}
public virtual ICollection Slots
{
get
{
return _ruleGroupSlots.Keys;
}
}
// omitted tons of stuff.. just included the relevant portion
protected int _id;
private IDictionary _ruleGroupSlots = new Dictionary<Slot, RuleGroupSlot>();
}
Code:
public class RuleGroupSlot
{
public virtual int Id
{
get { return _id; }
set { _id = value; }
}
public virtual RuleGroup RuleGroup
{
get { return _ruleGroup; }
set { _ruleGroup = value; }
}
public virtual Slot Slot
{
get { return _slot; }
set { _slot = value; }
}
public IProductList GetOrderedProducts()
{
ProductList productList = new ProductList();
productList.Products = CollectionsUtil.ToGenericList<Product>(OrderedProducts);
return productList;
}
public virtual IList OrderedProducts
{
get { return _orderedProducts; }
set
{
// remove null items which is caused when the product orders are not sequential
for (int ii = value.Count - 1; ii >= 0; ii--) {
if (value[ii] == null) {
value.RemoveAt(ii);
}
}
_orderedProducts = value;
}
}
public override bool Equals(object obj)
{
RuleGroupSlot other = obj as RuleGroupSlot;
return other != null ? other.Slot == Slot && other.RuleGroup == RuleGroup : false;
}
public override int GetHashCode()
{
return typeof(RuleGroupSlot).GetHashCode() ^
(Slot != null ? Slot.GetHashCode() : 0) ^
(RuleGroup != null ? RuleGroup.GetHashCode() : 0);
}
private int _id;
private IList _orderedProducts;
private RuleGroup _ruleGroup;
private Slot _slot;
}
I have a gut feeling this has something to do with the Dictionary object in the RuleGroup Class and/or the OrderedProducts list in the RuleGroupSlot hibernate mapping. Any help would be greatly appreciated. Thanks.