<?xml version="1.0" encoding="utf-8" ?>
<?xml-stylesheet type="text/xsl" href="RSS_xslt_style.asp" version="1.0" ?>
<rss version="2.0" xmlns:WebWizForums="http://syndication.webwiz.co.uk/rss_namespace/">
 <channel>
  <title>DevForce Community Forum : EntityAspect.PropertyChanged, Event bubbling and Dirtying Parent objects.</title>
  <link>http://www.ideablade.com/forum/</link>
  <description>This is an XML content feed of; DevForce Community Forum : DevForce 2009 : EntityAspect.PropertyChanged, Event bubbling and Dirtying Parent objects.</description>
  <pubDate>Thu, 21 May 2026 21:26:30 -700</pubDate>
  <lastBuildDate>Sun, 24 Jan 2010 14:23:48 -700</lastBuildDate>
  <docs>http://blogs.law.harvard.edu/tech/rss</docs>
  <generator>Web Wiz Forums 9.69</generator>
  <ttl>360</ttl>
  <WebWizForums:feedURL>www.ideablade.com/forum/RSS_post_feed.asp?TID=1590</WebWizForums:feedURL>
  <image>
   <title>DevForce Community Forum</title>
   <url>http://www.ideablade.com/forum/forum_images/IdeaBlade_logo_tm.png</url>
   <link>http://www.ideablade.com/forum/</link>
  </image>
  <item>
   <title>EntityAspect.PropertyChanged, Event bubbling and Dirtying Parent objects. : Interesting.  I hadn&amp;#039;t thought...</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1590&amp;PID=6120#6120</link>
   <description>
    <![CDATA[<strong>Author:</strong> <a href="http://www.ideablade.com/forum/member_profile.asp?PF=308" rel="nofollow">skingaby</a><br /><strong>Subject:</strong> 1590<br /><strong>Posted:</strong> 24-Jan-2010 at 2:23pm<br /><br />Interesting.  I hadn't thought about using the Saving handler for this.  I shall have to consider how that will work in our grid row model (yeuch).]]>
   </description>
   <pubDate>Sun, 24 Jan 2010 14:23:48 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1590&amp;PID=6120#6120</guid>
  </item> 
  <item>
   <title>EntityAspect.PropertyChanged, Event bubbling and Dirtying Parent objects. : Hi Simon - You have a typical...</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1590&amp;PID=6105#6105</link>
   <description>
    <![CDATA[<strong>Author:</strong> <a href="http://www.ideablade.com/forum/member_profile.asp?PF=482" rel="nofollow">WardBell</a><br /><strong>Subject:</strong> 1590<br /><strong>Posted:</strong> 21-Jan-2010 at 1:25pm<br /><br />Hi Simon - You have a typical case of (A) cross entity dependence and (B) aggregate entity.<DIV>&nbsp;</DIV><DIV>I'm not sure I would address either in the ways you have proposed. The moment I saw you listening for changes to EntityAspect.EntityState deep in a base class I tuned out. "Hitting a bug with a sledge hammer" I thought.&nbsp;Maybe I'm just lazy. Permit me to proceed (theoretically ... I haven't actually written this out) in a different manner.</DIV><DIV>&nbsp;</DIV><DIV>--- (A) ORDER TOTAL ---</DIV><DIV><DIV>&nbsp;</DIV><DIV>What affects the Order Total?</DIV><DIV>- Adding a detail</DIV><DIV>- Removing a detail</DIV><DIV>- Changing a detail's quanity, price, discount, ???</DIV><DIV>&nbsp;</DIV><DIV>Let's start with Add and Remove. Personally, because this is an Aggregate, I would channel all adding and removing of OrderDetails through the AggregateRoot. I would PREVENT any process from creating/deleting an OrderDetail independently. The best way to do that is in the public constructor of the OrderDetail. Make it throw an exception.</DIV><DIV>&nbsp;</DIV><DIV>Alternatively, you could throw an exception when anyone tries to set the OrderDetail's parent Order or parent OrderId.</DIV><DIV>&nbsp;</DIV><DIV>Order should sport AddDetail and RemoveDetail methods. Only Order has the ability to set the OrderDetail's parent OrderId (devise an internal method for the purpose).</DIV><DIV>&nbsp;</DIV><DIV>Now that you've channeled adding / deleting through the Order, there is no problem ensuring that Order raises property changed for OrderTotal during detail add/delete.</DIV><DIV>&nbsp;</DIV><DIV>Still want to ignore my advice? Well you can also arrange for the Order to listen to changes in its own OrderDetail collection. You will find that OrderDetailsProperty.GetValue(this) returns the RelatedEntityList&lt;OrderDetail&gt; which has a CollectionChanged event you can listen to. You should be able to hook this by writing your own Order default constructor.&nbsp;&nbsp;Haven't tried but should work.</DIV><DIV>&nbsp;</DIV><DIV>On to OrderDetail changes.</DIV><DIV>&nbsp;</DIV><DIV>On simple approach is to provide a RaiseOrderTotalChanged method on the Order. In the OrderDetail, you can override OnPropertyChanged and have it call RaiseOrderTotalChanged on its parent Order.</DIV><DIV>&nbsp;</DIV><DIV>Interesting, I would expect this to fire when adding a detail to a parent Order. You might only have to worry about how to notify the Order when you remove a detail.</DIV><DIV>&nbsp;</DIV></DIV><DIV>--- (B) A CHANGE TO ORDER DETAIL IS A CHANGE TO THE PARENT ORDER ---</DIV><DIV>&nbsp;</DIV><DIV>"Order", in this example, is what is known as an "Aggregate root entity". The Order Aggregate in this example consists of Order and its OrderDetails. They are an "Aggregate" because&nbsp;we have several entity types in a common graph that&nbsp;are always treated as a single thing. An aggregate always has a root (Order) in this case; the other members of the aggregate (OrderDetail in this case) cannot exist apart from the root entity.</DIV><DIV>&nbsp;</DIV><DIV>This fact, by the way, explains why Product is not in the Aggregate even though Product is clearly part of Order's extended object graph. A change to Product does not propagate to changes in all Orders of that product (at least not in our example&nbsp;Order management system).</DIV><DIV>&nbsp;</DIV><DIV>I think its important&nbsp; to treat each Aggregate entity individually.&nbsp; </DIV><DIV>&nbsp;</DIV><DIV>I would program for the Order Aggregate by itself. The pattern applies to other aggregates certainly. But I wouldn't drive the behavior we're discussing down to a base entity shared by all entities (except as noted below ... there is always an except :-)&nbsp; ).</DIV><DIV>&nbsp;</DIV><DIV>You can dirty the Order the moment a Detail changes. There are reasons to do this; perhaps you want it reflected immediately in the UI. Perhaps you need to know if the Order permits changes to one of its details!</DIV><DIV>&nbsp;</DIV><DIV>We already established a mechanism for the OrderDetail to notify its parent&nbsp;Order of changes. It might as well dirty the parent Order at the same time&nbsp;via the same call.&nbsp;As part of that call, it checks to see if the Order is in the Unchanged state; if it&nbsp;is, call <strong>Order.EntityAspect.SetModified()</strong> .</DIV><DIV>&nbsp;</DIV><DIV>If you need to ensure that no one modifies a locked down detail, you should do this in a custom, pre-set&nbsp;<strong>ValidationRule</strong>, defined for all properties of the OrderDetail.</DIV><DIV>&nbsp;</DIV><DIV>---</DIV><DIV>However, I would not rely exclusively on dirtying the Order when an OrderDetail changes. The user could undo the OrderDetail change in which case the Order may not be dirty. Or the user might call undo changes on the Order even though one of its details is still dirty. You want to be sure to have integrity and consistency at the moment of save. That's why I look to the EntityManager's SavingHandler.</DIV><DIV>&nbsp;</DIV><DIV>You have one right? You should. That's the place to validate the entities you are about to save before attempting to save them to the database.</DIV><DIV>&nbsp;</DIV><DIV>In the SavingHandler, I validate every entity scheduled for save. I do this by calling into each entity's ValidateForSave method. "But they don't have such a method" you protest. Indeed they don't. You should add it. It's a good BaseEntity method. </DIV><DIV>&nbsp;</DIV><DIV>Arguments to the ValidateForSave&nbsp; method include the (a) list of entities to save, (b) an empty list of entities to add to that list, and (c) an empty list of entities to remove from that list &#091;rarely needed&#093;. </DIV><DIV>&nbsp;</DIV><DIV>Within the ValidateForSave, you can add any other related entity (entities)&nbsp;to lists&nbsp;(b)&nbsp;or (c).</DIV><DIV>&nbsp;</DIV><DIV>Your saving handler, which is iterating over list (a),&nbsp;looks for (b) and (c) coming back from the validated entity&nbsp;and takes appropriate action to update list (a) before calling ValidateForSave on the next item.</DIV><DIV>&nbsp;</DIV><DIV>The point of this is that the Detail checks to see if its parent Order is in list&nbsp;(a). If not, it dirties the order (as described above), and&nbsp;adds the dirtied parent Order to list (b).</DIV><DIV>&nbsp;</DIV><DIV>Consequently, the SavingHandler will include the dirtied parent Order among its list of entities to save; don't forget that the SavingHandler must&nbsp;validate that dirty parent Order as well!</DIV><DIV>&nbsp;</DIV><DIV>I should write this as a separate post and sample. I've been meaning to for years.</DIV><DIV>&nbsp;</DIV><DIV>&nbsp;</DIV><DIV>&nbsp;</DIV>]]>
   </description>
   <pubDate>Thu, 21 Jan 2010 13:25:59 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1590&amp;PID=6105#6105</guid>
  </item> 
  <item>
   <title>EntityAspect.PropertyChanged, Event bubbling and Dirtying Parent objects. : Also, a couple of days ago I completely...</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1590&amp;PID=5978#5978</link>
   <description>
    <![CDATA[<strong>Author:</strong> <a href="http://www.ideablade.com/forum/member_profile.asp?PF=308" rel="nofollow">skingaby</a><br /><strong>Subject:</strong> 1590<br /><strong>Posted:</strong> 23-Dec-2009 at 9:36am<br /><br />Also, a couple of days ago I completely rewrote these classes to use an AfterSet interceptor.  The approach shown in this thread, however, should only fire once when the entity is first dirtied, by using an AfterSet interceptor it fires a gazillion times because it fires any time any property changes.  What's worse, if a property has an interceptor that changes another property, then everything fires twice.<span style="font-size:10px"><br /><br />Edited by skingaby - 23-Dec-2009 at 9:37am</span>]]>
   </description>
   <pubDate>Wed, 23 Dec 2009 09:36:43 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1590&amp;PID=5978#5978</guid>
  </item> 
  <item>
   <title>EntityAspect.PropertyChanged, Event bubbling and Dirtying Parent objects. : Here&amp;#039;s the problem:  Second,...</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1590&amp;PID=5977#5977</link>
   <description>
    <![CDATA[<strong>Author:</strong> <a href="http://www.ideablade.com/forum/member_profile.asp?PF=308" rel="nofollow">skingaby</a><br /><strong>Subject:</strong> 1590<br /><strong>Posted:</strong> 23-Dec-2009 at 9:35am<br /><br />Here's the problem:<br /><br />Second, when the EntityManager.SaveChangesAsync processes, the BaseEntity.EntityAspectPropertyChanged is called twice. Once for the EntityAspect.EntityState property, and once for the EntityAspect.IsChanged property. I assumed this was firing when these items are being reset after the save/replace process, but when the OrderDetail calls these, the test in the BaseChildEntity.EntityAspectPropertyChangedInternal &gt; if (e.PropertyName == "IsChanged" && this.EntityAspect.IsChanged) still returns true. Why? What am I doing wrong? How can I accomplish what I need? <br /><br />Or, more succinctly:  when SaveChangesAsync comes back and the entity is replaced by the EM, the IsChanges property is set to false and its event is fired, but the IsChanges getter is still returning true.  Why?]]>
   </description>
   <pubDate>Wed, 23 Dec 2009 09:35:11 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1590&amp;PID=5977#5977</guid>
  </item> 
  <item>
   <title>EntityAspect.PropertyChanged, Event bubbling and Dirtying Parent objects. : &amp;gt;&amp;gt;OK.  So here&amp;#039;s what...</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1590&amp;PID=5975#5975</link>
   <description>
    <![CDATA[<strong>Author:</strong> <a href="http://www.ideablade.com/forum/member_profile.asp?PF=4" rel="nofollow">GregD</a><br /><strong>Subject:</strong> 1590<br /><strong>Posted:</strong> 22-Dec-2009 at 11:50am<br /><br />&gt;&gt;<br>OK.  So here's what I expect to happen:  <br><br>For requirement A) When an OrderDetail is edited, theOrderDetail.EntityAspect.IsChanged property gets changed, which iscaught in BaseEntity.EntityAspectPropertyChanged, which then raises theOrderDetail.IsChanged property changed event, which is caught by theOrder.OrderDetailPropertyChanged event handler, which then raises theOrder.OrderTotal property changed event, which tells the UI bound toOrder.OrderTotal to refresh.<br><br>For requirement B) When an OrderDetail is edited, theEntityAspect.IsChanged property gets changed, which is caught inBaseEntity.EntityAspectPropertyChanged, which then delegates to theBaseChildEntity.EntityAspectPropertyChangedInternal, which callsSetModified() on the parent Order. Now, when the Order is saved, the EMwill save the Order and the changed OrderDetails all at once. When theEm.SaveChangesAsync is called, I expect all items to be saved and resetto EntityState = NotModified and IsChanged = false.<br><br>But, of course, it didn't work out that way.<br><br>First, is this just ridiculous? Am I doing something silly toaccomplish what I need? My actual problem is messier and morecomplicated than this, so I would love to hear someone say this is notinsane.<br>&lt;&lt;<br><br>It seems okay on paper, and you haven't said exactly what didn't work out. I might be tempted to do something a little more direct; e.g., when any property of the OrderDetail changes, just call SetModified() directly on the parent Order; and when any property on the OrderDetail that affects price changes, call OnPropertyChanged(OrderTotal), again directly, on the parent Order.<br><br>]]>
   </description>
   <pubDate>Tue, 22 Dec 2009 11:50:22 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1590&amp;PID=5975#5975</guid>
  </item> 
  <item>
   <title>EntityAspect.PropertyChanged, Event bubbling and Dirtying Parent objects. : This is a little bit weird.  We...</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1590&amp;PID=5949#5949</link>
   <description>
    <![CDATA[<strong>Author:</strong> <a href="http://www.ideablade.com/forum/member_profile.asp?PF=308" rel="nofollow">skingaby</a><br /><strong>Subject:</strong> 1590<br /><strong>Posted:</strong> 16-Dec-2009 at 7:56pm<br /><br />This is a little bit weird.  We have added a PropertyChanged handler to our base child entity so it can bubble events up to its parent object and bubble events for readonly properties.  <br />Please bear with me.  First I will explain why I need this foolishness.  Second, I will show the code.  Third, I will ask my question.<br /><br />I have two example requirements:<br />A) When any OrderDetail changes, the UI should refresh the OrderTotal; and<br />B) When any part of an Order or OrderDetail changes, the Order and the changed Order Details should be saved as a set.<br /><br />For A), When a user changes an OrderDetail:BaseChildEntity in the Order:BaseEntity, the readonly Order.OrderTotal property needs to fire a PropertyChanged("OrderTotal") event so the UI control that is bound to it will refresh.  In order to do this, I am capturing the Entity.EntityAspect.IsChanged property change in the child entity and bubbling it up from the EntityAspect to the parent.<br /><br />For B), When a user changes an OrderDetail:BaseChildEntity in the Order:BaseEntity, the Order should be marked as dirty (i.e. Order.EntityAspect.IsChanged) so that when saved, the Entity Manager will save the Order and the changed Order Details.<br /><br />To accomplish this, I have coded the following:<br /><br />1) In BaseEntity, which Order derives from:<br /><table width="99%"><tr><td><pre class="BBcode">public abstract class BaseEntity : Entity<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;protected BaseEntity()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;base.EntityAspect.PropertyChanged += EntityAspectPropertyChanged; // This is probably NOT the right place to do this, but until we can find something better, this seems to work.  Suggestions?<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private void EntityAspectPropertyChanged(object sender, PropertyChangedEventArgs e)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.EntityAspectPropertyChangedInternal(sender, e);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;protected virtual void EntityAspectPropertyChangedInternal(object sender, PropertyChangedEventArgs e)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (e.PropertyName == "IsChanged") //take the Entity.EntityAspect.IsChanged property change<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RaisePropertyChanged("IsChanged"); //and turn it into an Entity.IsChanged property change<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</pre></td></tr></table><br /><br />2) In BaseChildEntity, which OrderDetail derives from:<br /><table width="99%"><tr><td><pre class="BBcode">public abstract class BaseChildEntity : BaseEntity<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;protected abstract BaseEntity Parent { get; set; } <br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;protected override void EntityAspectPropertyChangedInternal(object sender, System.ComponentModel.PropertyChangedEventArgs e)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;base.EntityPropertyChangedInternal(sender, e);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (e.PropertyName == "IsChanged" && this.EntityAspect.IsChanged)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//entity just got dirtied, so dirty the parent too<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.Parent.EntityAspect.SetModified();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</pre></td></tr></table><br /><br />3) In OrderDetail:<br /><table width="99%"><tr><td><pre class="BBcode">public partial class OrderDetail<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;protected override BaseEntity Parent<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;get<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return Order; //Expose the RelatedEntity&gt;Order as this OrderDetail's Parent<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Order = value as Order;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</pre></td></tr></table><br /><br />4) In Order:<br /><table width="99%"><tr><td><pre class="BBcode">public partial class Order<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public double OrderTotal()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return Sum(this.OrderDetails);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private void OrderDetailPropertyChanged(object sender, PropertyChangedEventArgs e) //there is a horrible amount of code in this class that handles ensuring that this event handler is tied to each OrderDetail.PropertyChanged event.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.RaisePropertyChanged("OrderTotal");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />}</pre></td></tr></table><br /><br />OK.  So here's what I expect to happen:  <br /><br />For requirement A) When an OrderDetail is edited, the OrderDetail.EntityAspect.IsChanged property gets changed, which is caught in BaseEntity.EntityAspectPropertyChanged, which then raises the OrderDetail.IsChanged property changed event, which is caught by the Order.OrderDetailPropertyChanged event handler, which then raises the Order.OrderTotal property changed event, which tells the UI bound to Order.OrderTotal to refresh.<br /><br />For requirement B) When an OrderDetail is edited, the EntityAspect.IsChanged property gets changed, which is caught in BaseEntity.EntityAspectPropertyChanged, which then delegates to the BaseChildEntity.EntityAspectPropertyChangedInternal, which calls SetModified() on the parent Order.  Now, when the Order is saved, the EM will save the Order and the changed OrderDetails all at once.  When the Em.SaveChangesAsync is called, I expect all items to be saved and reset to EntityState = NotModified and IsChanged = false.<br /><br />But, of course, it didn't work out that way.<br /><br />First, is this just ridiculous?  Am I doing something silly to accomplish what I need?  My actual problem is messier and more complicated than this, so I would love to hear someone say this is not insane.<br /><br />Second, when the EntityManager.SaveChangesAsync processes, the BaseEntity.EntityAspectPropertyChanged is called twice.  Once for the EntityAspect.EntityState property, and once for the EntityAspect.IsChanged property.  I assumed this was firing when these items are being reset after the save/replace process, but when the OrderDetail calls these, the test in the BaseChildEntity.EntityAspectPropertyChangedInternal &gt; if (e.PropertyName == "IsChanged" && this.EntityAspect.IsChanged) still returns true.  Why?  What am I doing wrong?  How can I accomplish what I need?<br />Here's the call stack at that moment:<br /><br />Model.DomainModel!DomainModel.BaseChildEntity.EntityAspectPropertyChangedInternal(object sender = {IdeaBlade.EntityModel.EntityAspect}, System.ComponentModel.PropertyChangedEventArgs e = {System.ComponentModel.PropertyChangedEventArgs}) Line 39&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C#<br />&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Png.GcsAg.Model.DomainModel!Png.GcsAg.Model.DomainModel.BaseEntity.EntityAspect_PropertyChanged(object sender = {IdeaBlade.EntityModel.EntityAspect}, System.ComponentModel.PropertyChangedEventArgs e = {System.ComponentModel.PropertyChangedEventArgs}) Line 42 + 0x11 bytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C#<br />IdeaBlade.EntityModel.SL!IdeaBlade.EntityModel.EntityAspect.OnPropertyChanged(System.ComponentModel.PropertyChangedEventArgs args = {System.ComponentModel.PropertyChangedEventArgs}) + 0x45 bytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />IdeaBlade.EntityModel.SL!IdeaBlade.EntityModel.EntityAspect.add_PropertyChanged.AnonymousMethod(object o = {DealPricing: 18485}, System.ComponentModel.PropertyChangedEventArgs args = {System.ComponentModel.PropertyChangedEventArgs}) + 0x26 bytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />IdeaBlade.EntityModel.SL!IdeaBlade.EntityModel.EntityWrapper.OnEntityAspectPropertyChanged(string propertyName = "IsChanged") + 0x92 bytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />IdeaBlade.EntityModel.SL!IdeaBlade.EntityModel.EntityWrapper.EntityState.set(IdeaBlade.EntityModel.EntityState value = Unchanged) + 0x77 bytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />IdeaBlade.EntityModel.SL!IdeaBlade.EntityModel.EntityWrapper.ReplaceAll(IdeaBlade.EntityModel.EntityWrapper sourceEntity = {DealPricing: 18485}, bool copy = true) + 0x9f bytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />IdeaBlade.EntityModel.SL!IdeaBlade.EntityModel.EntityWrapper.ReplaceEntity(IdeaBlade.EntityModel.EntityWrapper sourceEntity = {DealPricing: 18485}, IdeaBlade.EntityModel.MergeStrategy mergeStrategy = OverwriteChanges) + 0x71 bytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />IdeaBlade.EntityModel.SL!IdeaBlade.EntityModel.EntityGroup.ImportEntity(IdeaBlade.EntityModel.EntityWrapper sourceWrapper = {DealPricing: 18485}, IdeaBlade.EntityModel.MergeStrategy mergeStrategy = OverwriteChanges) + 0x89 bytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />IdeaBlade.EntityModel.SL!IdeaBlade.EntityModel.EntityManager.SaveEntitiesPostProcessing(IdeaBlade.EntityModel.SaveWorkState workstate = {IdeaBlade.EntityModel.SaveWorkState}) + 0x795 bytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />IdeaBlade.EntityModel.SL!IdeaBlade.EntityModel.EntityManager.SaveChangesAsyncCore.AnonymousMethod(IdeaBlade.EntityModel.EntitySavedEventArgs args = {IdeaBlade.EntityModel.EntitySavedEventArgs}) + 0x51 bytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />IdeaBlade.EntityModel.SL!IdeaBlade.EntityModel.AsyncProcessor&lt;IdeaBlade.EntityModel.EntitySavedEventArgs&gt;.Execute.AnonymousMethod(object x = {IdeaBlade.EntityModel.EntitySavedEventArgs}) + 0x73 bytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&#091;Native to Managed Transition&#093;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&#091;Managed to Native Transition&#093;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />mscorlib.dll!System.Delegate.DynamicInvokeImpl(object&#091;&#093; args = {object&#091;1&#093;}) + 0xb4 bytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />mscorlib.dll!System.Delegate.DynamicInvoke(object&#091;&#093; args = {object&#091;1&#093;}) + 0x2a bytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />System.Windows.dll!System.Windows.Threading.DispatcherOperation.Invoke() + 0x47 bytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />System.Windows.dll!System.Windows.Threading.Dispatcher.Dispatch(System.Windows.Threading.DispatcherPriority priority = 13) + 0x161 bytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />System.Windows.dll!System.Windows.Threading.Dispatcher.OnInvoke(object context = null) + 0x28 bytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />System.Windows.dll!System.Windows.Hosting.CallbackCookie.Invoke(object&#091;&#093; args = {object&#091;0&#093;}) + 0x37 bytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />System.Windows.dll!System.Windows.Hosting.DelegateWrapper.InternalInvoke(object&#091;&#093; args = {object&#091;0&#093;}) + 0x2a bytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />System.Windows.Browser.dll!System.Windows.Hosting.ScriptingInterface.InvokeDelegate(System.Windows.Hosting.DelegateWrapper delegateWrapper = {System.Windows.Hosting.CallbackCookie}, System.Windows.Hosting.NativeMethods.ScriptParam&#091;&#093; pParams = {System.Windows.Hosting.NativeMethods.ScriptParam&#091;0&#093;}, ref System.Windows.Hosting.NativeMethods.ScriptParam pResult = {System.Windows.Hosting.NativeMethods.ScriptParam}) + 0x68 bytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />System.Windows.Browser.dll!System.Windows.Hosting.ManagedHost.InvokeDelegate(System.IntPtr pHandle = 151065016, int nParamCount = 0, System.Windows.Hosting.NativeMethods.ScriptParam&#091;&#093; pParams = {System.Windows.Hosting.NativeMethods.ScriptParam&#091;0&#093;}, ref System.Windows.Hosting.NativeMethods.ScriptParam pResult = {System.Windows.Hosting.NativeMethods.ScriptParam}) + 0x124 bytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&#091;Appdomain Transition&#093;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&#091;Native to Managed Transition&#093;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />Thanks, Simon.<br />]]>
   </description>
   <pubDate>Wed, 16 Dec 2009 19:56:34 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1590&amp;PID=5949#5949</guid>
  </item> 
 </channel>
</rss>