New Posts New Posts RSS Feed: When I call PersisteneManager.Clear() and then try to get some data, it messes the cache
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

When I call PersisteneManager.Clear() and then try to get some data, it messes the cache

 Post Reply Post Reply
Author
Customer View Drop Down
Senior Member
Senior Member
Avatar
User Submitted Questions to Support

Joined: 30-May-2007
Location: United States
Posts: 260
Post Options Post Options   Quote Customer Quote  Post ReplyReply Direct Link To This Post Topic: When I call PersisteneManager.Clear() and then try to get some data, it messes the cache
    Posted: 16-Jul-2007 at 3:28pm

Regarding PersistenceManager.Clear() issue:

When I call this method and then try to get some data, it messes the cache. We were getting this error consistently in the past. So we stopped using this function. I will try to reproduce the error and send you an email soon.

Back to Top
IdeaBlade View Drop Down
Moderator Group
Moderator Group
Avatar

Joined: 30-May-2007
Location: United States
Posts: 353
Post Options Post Options   Quote IdeaBlade Quote  Post ReplyReply Direct Link To This Post Posted: 16-Jul-2007 at 3:29pm
You have recently reported that you have been experiencing exceptions after doing a PM.Clear() operation,
 
When I call PM.Clear() and then try to get some data, it messes the cache. We were getting this error consistently in the past. So we stopped using this function. I will try to reproduce the error and send you an email soon.
 
I'd like to send you an analysis of this issue written by one of the company's founders.  I'm not saying that this anlysis will magically fix all of your problems, but I am saying that you should understand that while PM.Clear() will remove all of the entities from the cache, it does not clear any of the EntityLists.  I believe that your exceptions may be caused by the fact that after executing PM.Clear(), all of your EntityLists will contain a list of Detached Entities.  Trying to access a detached entity can easily cause an exception.
 
The following is an explanation as to why clearing a PM does not clear all EntityLists of the entities that live in that PM.
 
You've likely experienced this when a control or grid bound to an EntityList with entities in the cleared PM crashes.
 
Removing an entity from the PM does remove it from any EntityList that holds it, whether or not that EntityList is a managed list. All EntityLists remove detached entities when they see them become detached; you don't have to add a ListManager to enjoy this effect.
 
However, clearing the PM (which turns all its entities into detached entities) does not cause the EntityList to update itself.
 
The attached nunit test code demonstrates that fact and shows how to work around it (see ClearAllEntities).
 
We want to keep the current PM behavior because it is fast. An app that wants to clear a PM (rather than discard it) generally knows its EntityLists and can clear (or discard) them when it clears a PM. However, some apps are not designed to be sure that they know all of the EntityLists dependent on the PM.
 
We have a feature request to provide an alternative to PersistenceManager.Clear() that will achieve this purpose more efficiently.
 
Ward
 
----- UNIT TEST CODE AND WORKAROUND FOLLOWS ---

    /// <summary>Test that Clearing a PM also clears all EntityLists.</summary>
    [Test]
    public void PmClearTest() {
      PersistenceManager pm = new PersistenceManager(PersistenceManager.DefaultManager);
 
      // Read some entities so we can see what we're clearing;
      EntityList<Customer> custList = pm.GetEntities<Customer>();
      EntityList<Order> orderList = pm.GetEntities<Order>();
 
      EntityList<Employee> empList = new EntityList<Employee>();
      empList.ListChanged += new ListChangedEventHandler(empList_ListChanged); // listen for entities coming and going
 
      msListChangedContext = "initialize emplist"; // context in which list changed
      empList.ReplaceRange(pm.GetEntities<Employee>());
 
      int originalCount = empList.Count;
      Assert.Greater(originalCount, 0, "Got no emps.");
 

      msListChangedContext = "remove emp";
      Employee anEmp = empList[0];
      pm.RemoveEntity(anEmp, false);
      Assert.AreEqual(anEmp.RowState, DataRowState.Detached, "Removed emp is not detached.");
      Assert.AreEqual(originalCount - 1, empList.Count, "Should have had one fewer emp after remove");
 
      anEmp.AddToManager();
      msListChangedContext = "re-add emp to manager and then to list";
      empList.Add(anEmp);
 
      // DefectI think pm.Clear should be able to clear all EntityLists that it knows about automatically.
      // Because it doesn't, we use ClearAllEntities to get the job done.
      // Comment out the following 2 lines to see that PM doesn't clear the EntityLists and the tests fail.
      msListChangedContext = null; // Don't report list changed for as its items disappear individually
      ClearAllEntities(pm); // Clear the PM entities first
     
      msListChangedContext = "clear pm."; // Never shown because no ListChanged event on Pm.Clear()
      pm.Clear();
 
      Assert.IsTrue(empList.Count == 0, "Have emps in EntityList after PM clear.");
      Assert.IsTrue(custList.Count == 0, "Have customers in EntityList after PM clear.");
      Assert.IsTrue(orderList.Count == 0, "Have orders in EntityList after PM clear.");
    }
 
    #region PmClearTest Diagnostic
    private static string msListChangedContext = "Unknown context";
 
    static void empList_ListChanged(object sender, ListChangedEventArgs e) {
      if ( String.IsNullOrEmpty(msListChangedContext) ) return;
      Console.WriteLine("ListChanged fired in context: " + msListChangedContext);
    }
    #endregion
 
    #region ClearAllEntities
    /// <summary>Clears all entities in the Pm, also clearing associated EntityLists.</summary>
    /// <param name="pPm">The PersistenceManager we will clear.</param>
    /// <remarks>
    /// This method is useful when we want to clear a PersistenceManager (PM)
    /// and do not know what EntityLists contain entities currently resident in that PM.
    /// <para>
    /// An EntityList(Of T) cannot clear itself today
    /// when we clear the PM holding entities in that list.
    /// An EntityList only listens for changes to the rowstate of individual entities,
    /// not to the EntityTable.TableCleared event.
    /// Moreover, PersistenceManager.Clear does not clear individual EntityTables;
    /// rather it simply discards the tables themselves.
    /// </para>
    /// <para>
    /// This method iterates through all of the EntityTables of the PM
    /// and removes each entity of each table.
    /// </para>
    /// <para>
    /// This could be very slow; it would be better to keep track of our
    /// EntityLists and clear them before clearing the PM.
    /// However, it may not be possible to know all of the EntityLists with
    /// entities in the PM we are clearing.
    /// This method will take care of that because all EntityLists
    /// will "hear" our removal of the individual entities.
    /// </para>
    /// </remarks>
    private void ClearAllEntities(PersistenceManager pPm) {
      pPm.QueryCache.Clear(); // Query cache should be empty after this operation
      DataTableCollection pEntityTables = pPm.DataSet.Tables;
      foreach ( DataTable anEntityTable in pEntityTables ) {
        ClearEntityTable(anEntityTable);
      }
    }
 
    /// <summary>Clears the entities of the type, T, in the Pm, also clearing associated EntityLists.</summary>
    /// <typeparam name="T">The entity type to clear.</typeparam>
    /// <param name="pPm">The PersistenceManager holding instances of this Entity type.</param>
    private void ClearEntityType<T>(PersistenceManager pPm) where T : Entity {
      EntityTable table = pPm.GetTable(typeof(T));
      ClearEntityTable(table);
    }
 
    /// <summary>Clears the entities in the Entity table.</summary>
    private static void ClearEntityTable(DataTable pEntityTable) {
 
      // Diagnostic:
      Console.WriteLine("Clearing EntityTable: " + pEntityTable.TableName);
 
      // pEntityTable.Clear(); // doesn't work
 
      // must remove each entity individually
      DataRowCollection entities = pEntityTable.Rows;
      for ( int i = ( entities.Count - 1 ); i >= 0; i-- ) {
        entities.RemoveAt(i);
      }
    }
    #endregion
 
 

 

 


Edited by IdeaBlade - 16-Jul-2007 at 3:34pm
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down