B2016-130: Copy and paste replace steps causing missing and duplicate items in tree (problems with ‘NextItems’)

This commit is contained in:
2017-08-07 13:05:02 +00:00
parent e8ae40ef7f
commit 20a07c6a3e
12 changed files with 135 additions and 31 deletions

View File

@@ -142,7 +142,7 @@ namespace VEPROMS.CSLA.Library
sb.Append(Counts<Membership>(Membership.CountNotDisposed, Membership.CountNotFinalized));
sb.Append(Counts<MembershipInfo>(MembershipInfo.CountNotDisposed, MembershipInfo.CountNotFinalized));
sb.Append(Counts<MembershipInfoList>(MembershipInfoList.CountNotDisposed, MembershipInfoList.CountNotFinalized));
sb.Append(Counts<NextItems>(NextItems.CountNotDisposed, NextItems.CountNotFinalized));
//sb.Append(Counts<NextItems>(NextItems.CountNotDisposed, NextItems.CountNotFinalized));
sb.Append(Counts<Part>(Part.CountNotDisposed, Part.CountNotFinalized));
sb.Append(Counts<PartAudit>(PartAudit.CountNotDisposed, PartAudit.CountNotFinalized));
sb.Append(Counts<PartAuditInfo>(PartAuditInfo.CountNotDisposed, PartAuditInfo.CountNotFinalized));
@@ -353,7 +353,7 @@ namespace VEPROMS.CSLA.Library
sb.Append(Counts<Membership>(Membership.CountCreated, Membership.CountNotDisposed, Membership.CountNotFinalized));
sb.Append(Counts<MembershipInfo>(MembershipInfo.CountCreated, MembershipInfo.CountNotDisposed, MembershipInfo.CountNotFinalized));
sb.Append(Counts<MembershipInfoList>(MembershipInfoList.CountCreated, MembershipInfoList.CountNotDisposed, MembershipInfoList.CountNotFinalized));
sb.Append(Counts<NextItems>(NextItems.CountCreated, NextItems.CountNotDisposed, NextItems.CountNotFinalized));
//sb.Append(Counts<NextItems>(NextItems.CountCreated, NextItems.CountNotDisposed, NextItems.CountNotFinalized));
sb.Append(Counts<Part>(Part.CountCreated, Part.CountNotDisposed, Part.CountNotFinalized));
sb.Append(Counts<PartAudit>(PartAudit.CountCreated, PartAudit.CountNotDisposed, PartAudit.CountNotFinalized));
sb.Append(Counts<PartAuditInfo>(PartAuditInfo.CountCreated, PartAuditInfo.CountNotDisposed, PartAuditInfo.CountNotFinalized));

View File

@@ -254,9 +254,7 @@ namespace VEPROMS.CSLA.Library
{
using (Item fromitem = previousInfo == null ? null : previousInfo.Get())
{
ItemInfo nextInfo = null; // Check to see if the item is being inserted in the middle of some items.
if (previousInfo != null && previousInfo.NextItems != null && previousInfo.NextItems.Count > 0)
nextInfo = previousInfo.NextItems[0];
ItemInfo nextInfo = previousInfo.GetNext(); // Check to see if the item is being inserted in the middle of some items.
using (Item itm = Item.MakeItem(fromitem, cont))
{
newitemid = itm.ItemID;
@@ -1986,8 +1984,13 @@ namespace VEPROMS.CSLA.Library
get
{
ItemInfo temp = this;
while (temp.NextItems != null && temp.NextItems.Count > 0) temp = temp.NextItems[0];
return temp;
ItemInfo last = this;
while (temp != null)
{
last = temp;
temp = temp.GetNext();
}
return last;
}
}
public ItemInfo LastChild(E_FromType partType)

View File

@@ -2056,9 +2056,7 @@ namespace VEPROMS.CSLA.Library
get
{
if (PrintAllAtOnce) return GetNextItem();
if (NextItemCount > 0 && NextItems != null && NextItems.Count > 0)
return NextItems[0];
return null;
return GetNext();
}
}
private static void ResetOrdinal(int itemID)
@@ -2335,16 +2333,16 @@ namespace VEPROMS.CSLA.Library
newItemInfo.UpdateROText();
newItemInfo.UpdatePastedStepTransitionText();
// Add to tree
if (newItemInfo.NextItemCount > 0)
if (newItemInfo.NextItem != null)
{
using (ItemInfo itm = ItemInfo.Get(newItemInfo.NextItem.ItemID))
using (ItemInfo itm = ItemInfo.GetNonCached(newItemInfo.NextItem.ItemID))
{
itm.OnNewSiblingBefore(new ItemInfoInsertEventArgs(newItemInfo, ItemInfo.EAddpingPart.Before));
}
}
else if (newItemInfo.PreviousID != null)
{
using (ItemInfo itm2 = ItemInfo.Get((int)newItemInfo.PreviousID))
using (ItemInfo itm2 = ItemInfo.GetNonCached((int)newItemInfo.PreviousID))
{
itm2.OnNewSiblingAfter(new ItemInfoInsertEventArgs(newItemInfo, ItemInfo.EAddpingPart.After));
}

View File

@@ -264,6 +264,76 @@ namespace VEPROMS.CSLA.Library
foreach (ItemInfo tmp in _CacheByPrimaryKey[_ItemID.ToString()])
tmp._ItemDocVersionCount = -1; // This will cause the data to be requeried
}
// B2016-130: GetNext was added so that NextItems was not used for finding the next item in a list of iteminfos using 'nextitems'.
// When using 'nextitems' internal list data structures for items were not maintained consistently with the database items during
// some occurrences of copy/paste/delete.
[Serializable()]
private class PreviousIDCriteria
{
public PreviousIDCriteria(int? previousID)
{
_PreviousID = previousID;
}
private int? _PreviousID;
public int? PreviousID
{
get { return _PreviousID; }
set { _PreviousID = value; }
}
}
public ItemInfo GetNext()
{
try
{
ItemInfo tmp = DataPortal.Fetch<ItemInfo>(new PreviousIDCriteria(ItemID));
if (tmp.ErrorMessage == "No Record Found")
{
tmp.Dispose(); // Clean-up ItemInfo
tmp = null;
}
return tmp;
}
catch (Exception ex)
{
throw new DbCslaException("Error on ItemInfo.GetNext", ex);
}
}
private void DataPortal_Fetch(PreviousIDCriteria criteria)
{
if (_MyLog.IsDebugEnabled) _MyLog.DebugFormat("[{0}] ItemInfo.DataPortal_FetchPreviousID", GetHashCode());
try
{
using (SqlConnection cn = Database.VEPROMS_SqlConnection)
{
ApplicationContext.LocalContext["cn"] = cn;
using (SqlCommand cm = cn.CreateCommand())
{
cm.CommandType = CommandType.StoredProcedure;
cm.CommandText = "getNextItems";
cm.Parameters.AddWithValue("@PreviousID", criteria.PreviousID);
cm.CommandTimeout = Database.DefaultTimeout;
using (SafeDataReader dr = new SafeDataReader(cm.ExecuteReader()))
{
if (!dr.Read())
{
_ErrorMessage = "No Record Found";
return;
}
ReadData(dr);
}
}
// removing of item only needed for local data portal
if (ApplicationContext.ExecutionLocation == ApplicationContext.ExecutionLocations.Client)
ApplicationContext.LocalContext.Remove("cn");
}
}
catch (Exception ex)
{
if (_MyLog.IsErrorEnabled) _MyLog.Error("ItemInfo.DataPortal_FetchPreviousID", ex);
_ErrorMessage = ex.Message;
throw new DbCslaException("ItemInfo.DataPortal_Fetch", ex);
}
}
private int _NextItemCount = 0;
/// <summary>
/// Count of NextItems for this Item
@@ -578,6 +648,25 @@ namespace VEPROMS.CSLA.Library
throw new DbCslaException("Error on ItemInfo.Get", ex);
}
}
// B2016-130: Just get an item from the database, but don't add it to the cache because it gets
// freed (only use this in a 'using' statement).
public static ItemInfo GetNonCached(int itemID)
{
try
{
ItemInfo tmp = DataPortal.Fetch<ItemInfo>(new PKCriteria(itemID));
if (tmp.ErrorMessage == "No Record Found")
{
tmp.Dispose(); // Clean-up ItemInfo
tmp = null;
}
return tmp;
}
catch (Exception ex)
{
throw new DbCslaException("Error on ItemInfo.GetNonCached", ex);
}
}
#endregion
#region Data Access Portal
internal ItemInfo(SafeDataReader dr)

View File

@@ -64,7 +64,17 @@ namespace VEPROMS.CSLA.Library
for (int i = 0; i < Count; i++)
{
if (base[i] == sender)
{
// Added insert to fix when item is replaced and a 'delete' is done, the item needs inserted. Note
// that when text is modified, i.e. 'Changed', this code is not executed. Fixed B2016-130.
RefreshingList = true;
IsReadOnly = false;
Items.Insert(i, (sender as ItemInfo).MyPrevious);
IsReadOnly = true;
this.OnListChanged(new ListChangedEventArgs(ListChangedType.ItemChanged, i));
RefreshingList = false;
break;
}
}
}
private bool _Disposed = false;