New Posts New Posts RSS Feed: PersistenceManager.Clear() and EntityLists
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

PersistenceManager.Clear() and EntityLists

 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: PersistenceManager.Clear() and EntityLists
    Posted: 06-Jun-2007 at 1:11pm

Question:

I’ve noticed that when I invoke PersistenceManager.Clear(), DevForce does not clear all EntityLists of the entities that live in that PM.  Why is that, and what can I do if I want them cleared?

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: 06-Jun-2007 at 1:13pm

Answer:

You may have wondered 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 (as of January 2007) to provide an alternative to PersistenceManager.Clear() that will achieve this purpose more efficiently.

 

UNIT TEST CODE AND WORKAROUND

 


    /// <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);

 

      // Defect: I 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

Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down