<?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 : Conditional Object Saving?</title>
  <link>http://www.ideablade.com/forum/</link>
  <description>This is an XML content feed of; DevForce Community Forum : DevForce 2010 : Conditional Object Saving?</description>
  <pubDate>Sat, 11 Apr 2026 12:13:57 -700</pubDate>
  <lastBuildDate>Mon, 26 Apr 2010 13:56:46 -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=1741</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>Conditional Object Saving? : @ChuckC - Well I&amp;#039;ll be a...</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1741&amp;PID=6658#6658</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> 1741<br /><strong>Posted:</strong> 26-Apr-2010 at 1:56pm<br /><br />@ChuckC - Well I'll be a monkey's uncle.<DIV></DIV><DIV>&nbsp;</DIV><DIV>Of course we clear the Contact.CompanyId :-)</DIV><DIV>&nbsp;</DIV><DIV>Actually it makes perfect sense. Contact.Company is watching the EntityManager cache and responds when the dependent entity disappears. It's important in this example that Contact.CompanyId is nullable. If it were not, we would not know what value to use in resetting the CompanyId; I believe we would leave it as. If you had a sentinel value (e.g., zero), you'd have to set that yourself.</DIV><DIV>&nbsp;</DIV><DIV>@smi-mark - I will follow your lead to <a href="http://www.ideablade.com/forum/forum_posts.asp?TID=1752" target="_blank">http://www.ideablade.com/forum/forum_posts.asp?TID=1752</A>&nbsp;</DIV>]]>
   </description>
   <pubDate>Mon, 26 Apr 2010 13:56:46 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1741&amp;PID=6658#6658</guid>
  </item> 
  <item>
   <title>Conditional Object Saving? :  Ward wrote:    Iwould not...</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1741&amp;PID=6657#6657</link>
   <description>
    <![CDATA[<strong>Author:</strong> <a href="http://www.ideablade.com/forum/member_profile.asp?PF=705" rel="nofollow">chuckc</a><br /><strong>Subject:</strong> 1741<br /><strong>Posted:</strong> 26-Apr-2010 at 1:28pm<br /><br /><DIV><DIV><FONT color=#006600>Ward wrote: </FONT></DIV><DIV>&nbsp;</DIV><DIV><FONT color=#006600>&nbsp;&nbsp; I&nbsp;would not have guessed that</FONT></DIV><DIV><FONT color=#006600>&nbsp;</FONT></DIV><DIV><FONT color=#000099>&nbsp;&nbsp; "<FONT size=3><FONT face=Calibri>calling RejectChanges() on one entity affects other related entities (i.e. automatically clearing <I style="mso-bidi-font-style: normal">Contact</I>.CompanyId&nbsp;&nbsp;&nbsp; </FONT></FONT></FONT></DIV><DIV><FONT color=#000099><FONT size=3><FONT face=Calibri>&nbsp;&nbsp;&nbsp; when <I style="mso-bidi-font-style: normal">Company</I>.EntityAspect.RejectChanges is called)<SPAN style="mso-spacerun: yes">&nbsp;</SPAN></FONT></FONT>"</FONT></DIV><DIV><FONT color=#000099>&nbsp;</FONT></DIV><DIV><FONT color=#006600>&nbsp;&nbsp; Have you tested this? Are you sure? </FONT></DIV><DIV><FONT color=#006600>&nbsp;</FONT></DIV><DIV><DIV>Yes, I have tested it, though not extensively.&nbsp;It works as described in two different scenarios so far.&nbsp; </DIV><DIV>&nbsp;</DIV><DIV>I didn't find any examples demonstrating it's use (<EM>EntityManager</EM>.RejectChanges - yes;&nbsp; <EM>EntityAspect</EM>.RejectChanges - no).&nbsp; Do you think it bears further investigation?&nbsp; </DIV></DIV></DIV><span style="font-size:10px"><br /><br />Edited by chuckc - 26-Apr-2010 at 1:49pm</span>]]>
   </description>
   <pubDate>Mon, 26 Apr 2010 13:28:05 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1741&amp;PID=6657#6657</guid>
  </item> 
  <item>
   <title>Conditional Object Saving? : This has been a great read, with...</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1741&amp;PID=6653#6653</link>
   <description>
    <![CDATA[<strong>Author:</strong> <a href="http://www.ideablade.com/forum/member_profile.asp?PF=449" rel="nofollow">smi-mark</a><br /><strong>Subject:</strong> 1741<br /><strong>Posted:</strong> 26-Apr-2010 at 10:56am<br /><br />This has been a great read, with some very helpful information, as always, from Ward. I was wondering if you could expand on your notion of sharing a repository with multiple views. <br><br>I created a post in the general development section, so not to clutter this thread.]]>
   </description>
   <pubDate>Mon, 26 Apr 2010 10:56:56 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1741&amp;PID=6653#6653</guid>
  </item> 
  <item>
   <title>Conditional Object Saving? : A new EM in the popup VM makes...</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1741&amp;PID=6651#6651</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> 1741<br /><strong>Posted:</strong> 26-Apr-2010 at 9:25am<br /><br /><P>A new EM in the popup VM makes sense. But what about other scenarios? Many of us divide a complex screen into multiple views, each supported by its own VM. These VMs interoperate and it is convenient (not to mention performant) when these VMs share a common UoW.</P><DIV>I would not put this in my ViewModel. I don't like persistence concerns in my ViewModel anyway; makes them hard to test. I inject the persistence machinery (typically a Repository) during production and supply a fake during testing.</DIV><DIV>&nbsp;</DIV><DIV>You can shape your VMs so that you get a new Repository with each instantiation of some of them and you get a preexisting one for instantiation of others.</DIV><DIV>&nbsp;</DIV><DIV>I caution you about building complex base classes with lots of dependencies. "Favor composition over inheritance" they say ... and they are wise to say it.</DIV><DIV>&nbsp;</DIV><DIV>I see your point about pulling the Contact Company management into the Contact class. I think I would still delegate it to a ContactCompany class; to each his own.</DIV><DIV>&nbsp;</DIV><DIV>And thanks for switching to the Saving handler. That's why it's there. EndEditCore is strictly related to a particular edit cycle of which there may be many before you get to the Save. You may have a rollback along the way too. I'll sleep better knowing you moved the logic.</DIV><DIV>&nbsp;</DIV><DIV>Regards, W</DIV>]]>
   </description>
   <pubDate>Mon, 26 Apr 2010 09:25:28 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1741&amp;PID=6651#6651</guid>
  </item> 
  <item>
   <title>Conditional Object Saving? : We are making progress! I want...</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1741&amp;PID=6650#6650</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> 1741<br /><strong>Posted:</strong> 26-Apr-2010 at 9:13am<br /><br />We are making progress!&nbsp; I want to comment on other points but first an alert. <DIV>&nbsp;</DIV><DIV>I&nbsp;would not have guessed that</DIV><DIV>&nbsp;</DIV><DIV>"<FONT size=3><FONT face=Calibri><FONT color=#000099>calling RejectChanges() on one entity affects other related entities (i.e. automatically clearing <I style="mso-bidi-font-style: normal">Contact</I>.CompanyId when <I style="mso-bidi-font-style: normal">Company</I>.EntityAspect.RejectChanges is called)</FONT><SPAN style="mso-spacerun: yes">&nbsp;</SPAN></FONT></FONT>"</DIV><DIV>&nbsp;</DIV><DIV>Have you tested this? Are you sure? </DIV><DIV>&nbsp;</DIV><DIV>Obviously, I did not expect this. I&nbsp; thought that you had to clear the Company from Contact. Actually, it makes sense to me that we would do that for you&nbsp;Perhaps we're working smarter than I thought. Maybe I even wrote about this. Feeling senile today.</DIV><DIV>&nbsp;</DIV><DIV><DIV>Fun to discover something about one's own product ;-)</DIV></DIV><span style="font-size:10px"><br /><br />Edited by WardBell - 26-Apr-2010 at 9:13am</span>]]>
   </description>
   <pubDate>Mon, 26 Apr 2010 09:13:22 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1741&amp;PID=6650#6650</guid>
  </item> 
  <item>
   <title>Conditional Object Saving? : Thanks for your feedback &#8211; and...</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1741&amp;PID=6647#6647</link>
   <description>
    <![CDATA[<strong>Author:</strong> <a href="http://www.ideablade.com/forum/member_profile.asp?PF=705" rel="nofollow">chuckc</a><br /><strong>Subject:</strong> 1741<br /><strong>Posted:</strong> 26-Apr-2010 at 7:21am<br /><br /><P style="MARGIN: 0in 0in 10pt" =Ms&#111;normal><FONT size=3><FONT face=Calibri>Thanks for your feedback – and your opinions!<?: prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></FONT></FONT></P><P style="MARGIN: 0in 0in 10pt" =Ms&#111;normal><FONT size=3><FONT face=Calibri>I lumped the ContactCompany into a ContactRepository in my mind – sorry for the confusion.<o:p></o:p></FONT></FONT></P><P style="MARGIN: 0in 0in 10pt" =Ms&#111;normal><FONT size=3><FONT face=Calibri>The use of a new EntityManager per ViewModel to encapsulate a UnitOfWork seems reasonable; particularly since CheckpointManager has been deprecated.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>The goal is to isolate changes to data bound entities occurring in a popup dialog (for example) from the main entity cache until the user commits those changes (by selecting OK on the popup).<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Of course this wouldn’t be necessary in a ViewModel that is presenting read-only data, but if it’s not a performance burden, I’d prefer to incorporate it into a view model base class.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Does that sound reasonable?<o:p></o:p></FONT></FONT></P><P style="MARGIN: 0in 0in 10pt" =Ms&#111;normal><FONT size=3><FONT face=Calibri>EndEditCore is indeed being called at save time (in my tests at least) without any previous call to BeginEdit, but if that isn’t guaranteed, I won’t rely on it.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>I’m already iterating over the entities to be saved in an EntityManger.Saving event handler for other things, so adding a virtual PrepareSave method on my EntityBase class and calling it during save should get the job done.<o:p></o:p></FONT></FONT></P><P style="MARGIN: 0in 0in 10pt" =Ms&#111;normal><FONT size=3><FONT face=Calibri>Ahh – the connection between AcceptChanges and subsequent UPDATE versus INSERT actions is good to know.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>My half-baked testing thus far was only focusing on various create scenarios.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>And I didn’t realize that calling RejectChanges() on one entity affects other related entities (i.e. automatically clearing <I style="mso-bidi-font-style: normal">Contact</I>.CompanyId when <I style="mso-bidi-font-style: normal">Company</I>.EntityAspect.RejectChanges is called)<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>- that is much cleaner – thanks!<o:p></o:p></FONT></FONT></P><P style="MARGIN: 0in 0in 10pt" =Ms&#111;normal><FONT size=3><FONT face=Calibri>My focus on keeping the entity management code internal to the entities is driven partly by our development scenario.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>A developer on the team could slap a list of Contacts into an editable grid and expose something like Company.Name to the user.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>If I can make it behave as expected, allowing edits and throwing standard validation errors, it makes that developer’s life easier.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>They’re not going to need to be concerned whether they can bind to Company or have to use ContactCompany instead, and they won’t see (or maintain) the gunk inside the entities that makes it work.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>And, so far at least, I don’t see this sort of thing lead to any worse level of complexity in the entity classes than typical verification/validation.<o:p></o:p></FONT></FONT></P><P style="MARGIN: 0in 0in 10pt" =Ms&#111;normal><FONT size=3><FONT face=Calibri>Thanks again for your insights – much appreciated!<o:p></o:p></FONT></FONT></P>]]>
   </description>
   <pubDate>Mon, 26 Apr 2010 07:21:05 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1741&amp;PID=6647#6647</guid>
  </item> 
  <item>
   <title>Conditional Object Saving? :     I am a little confused...</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1741&amp;PID=6642#6642</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> 1741<br /><strong>Posted:</strong> 26-Apr-2010 at 1:47am<br /><br /><DIV></DIV><DIV></DIV><DIV></DIV>&nbsp; <DIV>I am a little confused by your response. I thought I answered your question directly with an extended discussion of using a surrogate for the Company associated with the Contact ... a ContactCompany helper class. </DIV><DIV>&nbsp;</DIV><DIV>The word "respository" doesn't appear until the last sentence ... and in a manner that does not pretend to speak to the matter of protecting entities from unwanted changes.&nbsp; I'll take that up below.</DIV><DIV>&nbsp;</DIV><DIV>I do not know if creating a new EntityManager (EM)&nbsp;for each VM is a good idea in your application. Certainly not something I have ever done nor would typically choose to do.</DIV><DIV>&nbsp;</DIV><DIV>I'm talking specifically about the granularity of VM. I agree that an EM is a terrific sandbox for accumulating and isolating a user's changes in one workflow from the changes that user is making in another workflow taking place "at the same time". A travel agent, for example, could be working on several bookings at once, each of them progressing independently and each of which may either be saved or discarded independently.</DIV><DIV>&nbsp;</DIV><DIV>--</DIV><DIV>&nbsp;</DIV><DIV>Calling EndEditCore is intentional. You could call EM.SaveChanges any time. If you were in the middle of an edit and the UI has not committed its changes, we're in a tough spot. Do we commit the changes for you? We figure that's what you want us to do. So we do it.</DIV><DIV>&nbsp;</DIV><DIV>But I wouldn't count on this being called by EVERY SaveChanges. In principle it need only be called if something had called BeginEdit first ... and only certain UIs do that.</DIV><DIV>&nbsp;</DIV><DIV>I think you only want to perform special logic to evaluate whether this is a real Contact Company during the Save. The proper way to do that is to handle the <strong>EntityManager.Saving</strong> event.</DIV><DIV>&nbsp;</DIV><DIV>You want to learn about that event.&nbsp;If you intend to validate entities on the client before save, you have to write a Saving handler that iterates over the entities-to-be-saved and validates them. Client-side validation is not automatic (as it is on the server) ... not as I write this although we may add this feature in future.</DIV><DIV>&nbsp;</DIV><DIV>--</DIV><DIV>&nbsp;</DIV><DIV>YIKES! </DIV><DIV>&nbsp;</DIV><DIV>I cannot see how your Company.Create method can work. You create&nbsp;a new Company&nbsp;and then you pretend (via "AcceptChanges") that it exists in the database. If you subsequently change the company and then try to save, you will cause DevForce and EF to attempt a database UPDATE for a table row that doesn't exist. This should fail.</DIV><DIV>&nbsp;</DIV><DIV>If this code actually works, it must be because of something I am not seeing.</DIV><DIV>&nbsp;</DIV><DIV>Meanwhile, even if it did succeed, the Company.IsNew flag is still true. After a save, something should set it false. I don't see what does that.</DIV><DIV>&nbsp;</DIV><DIV>And then there is the problem that you have not destroyed these new Companies that you are creating and then detaching from Contact. They linger on in the EntityManager, unnamed and Contact-less. Harmless now, perhaps, but looks like a landmine to me.</DIV><DIV>&nbsp;</DIV><DIV>Please don't do it this way. See below.</DIV><DIV>&nbsp;</DIV><DIV>--</DIV><DIV>&nbsp;</DIV><DIV>EntityAspect.EntityState tells you if the entity is new (is "added")&nbsp;but it doesn't tell you if someone has made changes since you created the entity.</DIV><DIV>&nbsp;</DIV><DIV>I've seen interest in that distinction before ... usually in the context of this same intent of yours to create a related entity but keep that entity only if the user "filled it in".</DIV><DIV>&nbsp;</DIV><DIV>Suppose you don't like my ContactCompany idea. Suppose you prefer to create a Customer, defensively,&nbsp;and then delete it if it is never used. May I suggest another approach?</DIV><OL><LI>Add&nbsp;an <strong><EM>internal</EM></strong>&nbsp;"IsNewAndUnchanged" flag to the Company; it will be false by default. Do not make it public.</LI><LI>Set it "true" at the end of&nbsp;your Company.Create</LI><LI>Set it "false"&nbsp;if and when there is any subsequent change to this Company entity</LI><LI>In the EntityManager.Saving event handler, ask the Contact to prepare itself for save (e.g., validate itself)</LI><LI>Such preparation can test its Company's IsNewAndUnchanged flag; if that is true, you call contact.Company.EntityAspect.RejectChanges() and it will go away.</LI><LI>You should have a validation rule that prevents saving of a Company for which this flag is true without regard for whether it is the child of a Contact; chances are you don't want such a thing in your database.</LI></OL><DIV>Observe that this flag is always false for queried and saved entities. It can only be true when you have created a Company and not touched it.</DIV><DIV>&nbsp;</DIV><DIV>Don't&nbsp;bother with&nbsp;breaking the relationship or killing off this Company until you are ready to save. Forget about EndEditCore. </DIV><DIV>&nbsp;</DIV><DIV>You are probably wondering how to implement step #3. How do you know if there is a subsequent change to the Company?</DIV><DIV>&nbsp;</DIV><DIV>I can think of several ways but the best, I think, is to attach an event handler to the PropertyChanged event in Company and clear the flag. If you want to get fancy, your&nbsp;event handler can detach itself from the event once it has cleared the flag. </DIV><DIV>&nbsp;</DIV><DIV>Alternatively, you could override the OnPropertyChanged method and clear the flag there (sure you'll clear it forever for every Company but the cost is negligable).</DIV><DIV>&nbsp;</DIV><DIV>--</DIV><DIV>&nbsp;</DIV><DIV>You wrote:</DIV><DIV>"<FONT size=3 face=Calibri><FONT color=#003399>Company it is still exposed as a property on Contact and potentially subject to direct manipulation elsewhere in the application, such as clearing its Name property.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>I need to handle&nbsp;those kinds of&nbsp;scenarios too</FONT>.</FONT>"</DIV><DIV>&nbsp;</DIV><DIV>If this is your worry than you may want to hide the Contact.Company property and drag the ContactCompany helper into the Contact class. I still think this is better than incorporating all that conditional code (my 1-6) inside the Contact; it really doesn't have anything to do with Contact per se; the concerns are about plumbing of the related Company. I wouldn't want all that code gunking up my Contact entity.</DIV><DIV>&nbsp;</DIV><DIV>Let's step back a second though. Are you really worried about&nbsp; the "potential for direct manipulation" of related enties all over the application? You asked about how the UI could be built such that it would not require you to deal with phantom "new Company" objects. I responded to that one use case.</DIV><DIV>&nbsp;</DIV><DIV>But protecting an entity against unwanted manipulation of its related entities by non-UI components? If you're really worried about that , you may be using the wrong technology. You might prefer something like Command Query Responsibility Separation (CQRS) in which you query for read-only DTOs and you always edit and save with other DTOs. </DIV><DIV>&nbsp;</DIV><DIV>You'll be chucking out the baby with the bathwater in my opinion; it's a lot more work than its proponents acknowledge. But it gives you the <EM><strong>potential</strong></EM> for the kind of safety that you're talking about without having to play games with creating and deleting entities. </DIV><DIV>&nbsp;</DIV><DIV>I don't know. I'm a little concerned that you'll over-architect this and end up with giant entity classes crowded with plumbing.</DIV><DIV>&nbsp;</DIV><DIV>Please remember that you asked for my opinion ... which you are free to take or not.</DIV>]]>
   </description>
   <pubDate>Mon, 26 Apr 2010 01:47:04 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1741&amp;PID=6642#6642</guid>
  </item> 
  <item>
   <title>Conditional Object Saving? : Thanks for your thoughtful reply....</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1741&amp;PID=6640#6640</link>
   <description>
    <![CDATA[<strong>Author:</strong> <a href="http://www.ideablade.com/forum/member_profile.asp?PF=705" rel="nofollow">chuckc</a><br /><strong>Subject:</strong> 1741<br /><strong>Posted:</strong> 25-Apr-2010 at 11:56am<br /><br /><P style="MARGIN: 0in 0in 10pt" ="Ms&#111;normal"><FONT size=3><FONT face=Calibri>Thanks for your thoughtful reply. </P><DIV></FONT></FONT><FONT size=3><FONT face=Calibri>I agree wholeheartedly that the logic for creating and managing Entities should not be&nbsp;in the UI; <SPAN style="mso-spacerun: yes">&nbsp;</SPAN>my hope is to include it in the entities themselves.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>A Repository is great for keeping a clean separation of domain and data access, but is not really what I was hoping to learn from my question.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Also, the repository mediated solution you advocate does not address how to handle some minor variations on the scenarios you describe.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>For example, unless I remove the relationship between Contact and Company, Company it is still exposed as a property on Contact and potentially subject to direct manipulation elsewhere in the application, such as clearing its Name property.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>I need to handle&nbsp;those kinds of&nbsp;scenarios too.</FONT></FONT></DIV><DIV><FONT size=3><FONT face=Calibri>&nbsp;</FONT></FONT></DIV><DIV><FONT size=3><FONT face=Calibri>My architecture creates a new EntityMangager in each ViewModel, leveraging IEditable to handle undo/cancel type of activities you mention in your item 6) above.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Items 1 – 5 I want to handle in the entities themselves, possibly in an override of EndEditCore.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN><O:P></O:P></FONT></FONT></DIV><FONT size=3><FONT face=Calibri><DIV>&nbsp;</DIV><DIV>BTW, I’ve noticed that EndEditCore is automatically invoked when EntityManager.SaveChanges is called.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>This is convenient for me, though somewhat unexpected; <SPAN style="mso-spacerun: yes">&nbsp;</SPAN>is this intentional?</DIV><DIV>&nbsp;<O:P></O:P></FONT></FONT></DIV><FONT size=3><FONT face=Calibri><DIV>Below is an approach that tests successfully – I’d appreciate any feedback. <SPAN style="mso-spacerun: yes">&nbsp;</SPAN>Note that I injected a custom EntityBase class whose sole purpose is to track New state.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>I was unable to find a way to track “dirty” independent of “new” with the existing EntityState features – am I missing something?</DIV><DIV>&nbsp;<O:P></O:P></FONT></FONT></DIV><P style="MARGIN: 0in 0in 10pt" ="Ms&#111;normal"><FONT size=3><FONT face=Calibri>Basically what I am doing is setting a Company to “new” and “not dirty” when initially created, but then breaking the Contact/Company relationship at Contact save time if it is still new and unchanged.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>I plan to deal with the scenario of clearing an existing&nbsp;Company name, etc. through validation rules. <SPAN style="mso-spacerun: yes">&nbsp;</SPAN>This will employ significant logic involving other aspects of Contact/Company not discussed here.&nbsp; And regardless of any wrapper layers, I believe that kind of validation checking belongs directly in the model objects, as the Validation subsystem seems to provide for.<O:P></O:P></FONT></FONT></P><P style="MARGIN: 0in 0in 10pt" ="Ms&#111;normal"><B style="mso-bidi-font-weight: normal"><FONT size=3><FONT face=Calibri>Contact.cs<O:P></O:P></FONT></FONT></B></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; COLOR: blue; FONT-SIZE: 9.5pt">namespace</SPAN><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"> DomainModel<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt">{<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">public</SPAN> <SPAN style="COLOR: blue">partial</SPAN> <SPAN style="COLOR: blue">class</SPAN> <SPAN style="COLOR: #2b91af">Contact</SPAN> : <SPAN style="COLOR: #2b91af">EntityBase</SPAN><O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>{<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN></SPAN><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes"> </SPAN><SPAN style="COLOR: blue">public</SPAN> <SPAN style="COLOR: blue">static</SPAN> <SPAN style="COLOR: #2b91af">Contact</SPAN> Create(<SPAN style="COLOR: #2b91af">iCatalystEntityManager</SPAN> manager)<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>{<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #2b91af">Contact</SPAN> contact = manager.CreateEntity&lt;<SPAN style="COLOR: #2b91af">Contact</SPAN>&gt;();<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>contact.ContactId = <SPAN style="COLOR: #2b91af">Guid</SPAN>.NewGuid();<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>contact.EntityAspect.AddToManager();<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><O:P>&nbsp;</O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>contact.Company = <SPAN style="COLOR: #2b91af">Company</SPAN>.Create(manager);<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><O:P>&nbsp;</O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">return</SPAN> contact;<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><O:P>&nbsp;</O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><O:P>&nbsp;</O:P></SPAN><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: gray">///</SPAN><SPAN style="COLOR: green"> </SPAN><SPAN style="COLOR: gray">&lt;summary&gt;</SPAN><O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: gray">///</SPAN><SPAN style="COLOR: green"> Called upon SaveChanges regardless of whether BeginEdit was called previously or not.</SPAN><O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: gray">///</SPAN><SPAN style="COLOR: green"> </SPAN><SPAN style="COLOR: gray">&lt;/summary&gt;</SPAN><O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">protected</SPAN> <SPAN style="COLOR: blue">override</SPAN> <SPAN style="COLOR: blue">void</SPAN> EndEditCore()<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>{<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">base</SPAN>.EndEditCore();<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><O:P>&nbsp;</O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">if</SPAN> (!Company.EntityAspect.HasChanges() &amp;&amp;&nbsp;</SPAN><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt">Company.IsNew)<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>{</P><DIV><FONT color=#808080>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; //</FONT><SPAN style="COLOR: green"> Break the Contact-Company link</SPAN><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN>CompanyId = <SPAN style="COLOR: blue">null</SPAN>;</SPAN></SPAN><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"></P></DIV><DIV></SPAN><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}<O:P></O:P></SPAN></DIV><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>}<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt">}<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><O:P>&nbsp;</O:P></SPAN></P><P style="MARGIN: 0in 0in 10pt" ="Ms&#111;normal"><B style="mso-bidi-font-weight: normal"><FONT size=3><FONT face=Calibri>Company.cs<O:P></O:P></FONT></FONT></B></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; COLOR: blue; FONT-SIZE: 9.5pt">namespace</SPAN><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"> DomainModel<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt">{<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">public</SPAN> <SPAN style="COLOR: blue">partial</SPAN> <SPAN style="COLOR: blue">class</SPAN> <SPAN style="COLOR: #2b91af">Company</SPAN> : <SPAN style="COLOR: #2b91af">EntityBase</P><DIV></SPAN></SPAN><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>{<O:P></O:P></SPAN></DIV><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">public</SPAN> <SPAN style="COLOR: blue">static</SPAN> <SPAN style="COLOR: #2b91af">Company</SPAN> Create(<SPAN style="COLOR: #2b91af">iCatalystEntityManager</SPAN> manager)<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>{<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #2b91af">Company</SPAN> company = manager.CreateEntity&lt;<SPAN style="COLOR: #2b91af">Company</SPAN>&gt;();<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>company.CompanyId = <SPAN style="COLOR: #2b91af">Guid</SPAN>.NewGuid();<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><O:P>&nbsp;</O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>company.EntityAspect.AddToManager();</P><DIV></SPAN><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="COLOR: gray"></SPAN></SPAN>&nbsp;</DIV><DIV><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="COLOR: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</SPAN><SPAN style="COLOR: green"> Initialize to a "new" and "not dirty" state</SPAN></SPAN></DIV><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>company.EntityAspect.AcceptChanges();<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>company.IsNew = <SPAN style="COLOR: blue">true</SPAN>;<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><O:P>&nbsp;</O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">return</SPAN> company;<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>}<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt">}<O:P></O:P></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><O:P>&nbsp;</O:P></SPAN></P><span style="font-size:10px"><br /><br />Edited by chuckc - 25-Apr-2010 at 8:15pm</span>]]>
   </description>
   <pubDate>Sun, 25 Apr 2010 11:56:38 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1741&amp;PID=6640#6640</guid>
  </item> 
  <item>
   <title>Conditional Object Saving? : Great question!   My answer,...</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1741&amp;PID=6603#6603</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> 1741<br /><strong>Posted:</strong> 22-Apr-2010 at 2:32pm<br /><br />Great question! <DIV>&nbsp;</DIV><DIV>My answer, as you will see, is never create the company unless you mean it.</DIV><DIV>&nbsp;</DIV><DIV>If, as here, a Contact is not required to have a Company, don't create one until (and unless) you are certain that the Contact should have a Company.</DIV><DIV>&nbsp;</DIV><DIV>That means you should not expose the Contact.Company entity to binding!</DIV><DIV>&nbsp;</DIV><DIV>As you've discovered, you get into all kinds of trouble trying&nbsp;to manage whether you do or do not have a Company. Avoid this altogether.</DIV><DIV>&nbsp;</DIV><DIV>Instead write yourself a "ContactCompany" class in support of this editor. Note that ContactCompany is NOT an entity. It isn't part of your domain model either. It is a helper class for this particular corner of your UI.</DIV><DIV>&nbsp;</DIV><DIV>Let me&nbsp;assume that you are&nbsp;using the MVVM (Model / View / ViewModel) pattern for your editor. </DIV><DIV>&nbsp;</DIV><DIV>The ViewModel (VM) would have a Contact and a ContactCompany property. When your VM&nbsp;acquires the Contact (prior to presenting it to the user), it instantiates a ContactCompany object and populates it according to whether the Contact has ... or does not have ... a Company.</DIV><DIV>&nbsp;</DIV><DIV>Your view binds to both the VM.Contact and the VM.ContactCompany properties. The view widgets bind to these objects as appropriate.</DIV><DIV>&nbsp;</DIV><DIV>Important: the "Company" related widgets bind to the ContactCompany, NOT to Contact.Company!</DIV><DIV>&nbsp;</DIV><DIV>When the user does something that would trigger you to "commit" the input, the VM asks the ContactCompany to commit. The ContactCompany.Commit might do one of the following:</DIV><DIV>&nbsp;</DIV><DIV>1) If the Contact.Company pre-existed, update it based on values entered by the user that are now in ContactCompany&nbsp;</DIV><DIV>&nbsp;</DIV><DIV>2) If there was no Contact.Company entity before and the user entered valid Company info, your ContactCompany object creates a new Company (but see note below), populates it, and adds the new Company to the Contact.</DIV><DIV>&nbsp;</DIV><DIV>3) If the user did nothing to indicate that there should be a Contact.Company ... do nothing. No residual entity effects to worry about.</DIV><DIV>&nbsp;</DIV><DIV>4) If there was no pre-existing Contact.Company and the user had entered some company info, causing there to now be a new Company (not yet saved) per #2 ....&nbsp;and then the user erases the company name ... your ContactCompany will have to clean up. Most likely it will detach the new Company it created from the Contact ... and then delete that Company.</DIV><DIV>&nbsp;</DIV><DIV>5) If there <U>was</U> a pre-existing Contact.Company and the user erases the ContactCompany Name and the Contact.Company existed ... well you have to decide what that means :-).&nbsp; </DIV><DIV>&nbsp;</DIV><DIV>If you allow it ... and this means that the Company should be deleted (are you sure?) ... then ContactCompany detaches the Company and "deletes it" (which means that it will be deleted from the database when you save).</DIV><DIV>&nbsp;</DIV><DIV>6) After #5, (a) the user changes her mind and wants to keep the company or (b)&nbsp;&nbsp;the user starts entering new company information .... you have another decision to make.&nbsp; </DIV><DIV>&nbsp;</DIV><DIV>You might decide to undo the deletion of the previous Company and apply the user's changes to this resurrected Company.</DIV><DIV>&nbsp;</DIV><DIV>Or you might decide to proceed as in #2 ... in which case you have an old company slated for deletion (#5)&nbsp;and a new company ready for insertion (#2).</DIV><DIV>&nbsp;</DIV><DIV>The&nbsp;complexity represented in #6 can be eliminated if you save the user's work when the user commits any of #1 - #5. </DIV><DIV>--</DIV><DIV>&nbsp;</DIV><DIV>As you see, I'm asking you to encapsulate all of&nbsp;these UI decisions inside your ContactCompany class. None of them have to do with the domain model per se; they aren't "business logic". They are the logic of how your UI works. You are gathering user input ... learning what the user wants you to do.</DIV><DIV>&nbsp;</DIV><DIV>Of course the user's wishes expressed through that UI logic will&nbsp;result in <EM>changes to</EM> the domain model; but that is different from logic <EM>intrinsic</EM> to the model.</DIV><DIV>&nbsp;</DIV><DIV>The distinction between <EM>changes to</EM> the model and <EM>logic in</EM> the model is crucial. I hope it helps you to see why you want to delay creating/deleting/updating the Contact's Company entity until the user's intentions are clear.</DIV><DIV>&nbsp;</DIV><DIV>--</DIV><DIV>&nbsp;</DIV><DIV>I also recommend that&nbsp;the logic for creating&nbsp;new Contact and Company entities be kept out of the UI. This logic belongs either in the entities themselves (as you have shown in your static factory methods) or in&nbsp;methods of a separate&nbsp;factory class.&nbsp;Entity creation <EM>is</EM>&nbsp;a concern of the&nbsp;Domain Model, not the UI.&nbsp;</DIV><DIV>&nbsp;</DIV><DIV>More generally, I firmly believe that NO CLASS IN THE UI LAYER should ever refer directly&nbsp;to the EntityManager and certainly never ask it to create something. I strongly encourage you to move queries and saves and maybe more complexe entity creation into a helper class such as a Repository or a "DataService" class.</DIV><span style="font-size:10px"><br /><br />Edited by WardBell - 22-Apr-2010 at 2:36pm</span>]]>
   </description>
   <pubDate>Thu, 22 Apr 2010 14:32:36 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1741&amp;PID=6603#6603</guid>
  </item> 
  <item>
   <title>Conditional Object Saving? : Consider a typical WPF application...</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1741&amp;PID=6598#6598</link>
   <description>
    <![CDATA[<strong>Author:</strong> <a href="http://www.ideablade.com/forum/member_profile.asp?PF=705" rel="nofollow">chuckc</a><br /><strong>Subject:</strong> 1741<br /><strong>Posted:</strong> 21-Apr-2010 at 8:50pm<br /><br /><P style="MARGIN: 0in 0in 10pt" =Ms&#111;normal><FONT size=3><FONT face=Calibri>Consider a typical WPF application where you display a screen with contact information.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>On the screen are multiple textbox controls bound to, for example, Contact.FirstName, Contact.LastName and Contact.Company.Name.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>The Name field on Company is required, but the Company property/FK relation is nullable.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>The user supplies input to the LastName and FirstName fields, and leaves the Company.Name field empty, since this particular contact has no company affiliation.<?: prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></FONT></FONT></P><P style="MARGIN: 0in 0in 10pt" =Ms&#111;normal><FONT size=3><FONT face=Calibri>How would you recommend handling this situation to allow Contact to save, while recognizing the Company should not be saved (in fact, cannot be saved since a value for Name has not been provided)?<o:p></o:p></FONT></FONT></P><P style="MARGIN: 0in 0in 10pt" =Ms&#111;normal><FONT size=3><FONT face=Calibri>I show my very standard Create methods for Contact and Company below.<o:p></o:p></FONT></FONT></P><P style="MARGIN: 0in 0in 10pt" =Ms&#111;normal><FONT size=3><FONT face=Calibri><SPAN style="mso-spacerun: yes">&nbsp;</SPAN>In the Contact class:<o:p></o:p></FONT></FONT></P><P style="LINE-HEIGHT: normal; TEXT-INDENT: 0.5in; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" =Ms&#111;normal><SPAN style="FONT-FAMILY: C&#111;nsolas; COLOR: blue; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;</SPAN>public</SPAN><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"> <SPAN style="COLOR: blue">static</SPAN> <SPAN style="COLOR: #2b91af">Contact</SPAN> Create(IbEm.<SPAN style="COLOR: #2b91af">EntityManager</SPAN> manager)<o:p></o:p></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" =Ms&#111;normal><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>{<o:p></o:p></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" =Ms&#111;normal><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #2b91af">Contact</SPAN> contact = manager.CreateEntity&lt;<SPAN style="COLOR: #2b91af">Contact</SPAN>&gt;();<o:p></o:p></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" =Ms&#111;normal><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>contact.ContactId = <SPAN style="COLOR: #2b91af">Guid</SPAN>.NewGuid();<o:p></o:p></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" =Ms&#111;normal><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>contact.EntityAspect.AddToManager();<o:p></o:p></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" =Ms&#111;normal><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><o:p>&nbsp;</o:p></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" =Ms&#111;normal><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>contact.Company = <SPAN style="COLOR: #2b91af">Company</SPAN>.Create(contact.EntityManager);<o:p></o:p></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" =Ms&#111;normal><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><o:p>&nbsp;</o:p></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" =Ms&#111;normal><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">return</SPAN> contact;<o:p></o:p></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" =Ms&#111;normal><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}<o:p></o:p></SPAN></P><P style="MARGIN: 0in 0in 10pt" =Ms&#111;normal><o:p><FONT size=3 face=Calibri>&nbsp;</FONT></o:p></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" =Ms&#111;normal><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt">In the Company class:<o:p></o:p></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" =Ms&#111;normal><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><o:p>&nbsp;</o:p></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" =Ms&#111;normal><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">public</SPAN> <SPAN style="COLOR: blue">static</SPAN> <SPAN style="COLOR: #2b91af">Company</SPAN> Create(IbEm.<SPAN style="COLOR: #2b91af">EntityManager</SPAN> manager)<o:p></o:p></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" =Ms&#111;normal><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>{<o:p></o:p></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" =Ms&#111;normal><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #2b91af">Company</SPAN> company = manager.CreateEntity&lt;<SPAN style="COLOR: #2b91af">Company</SPAN>&gt;();<o:p></o:p></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" =Ms&#111;normal><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>company.CompanyId = <SPAN style="COLOR: #2b91af">Guid</SPAN>.NewGuid();<o:p></o:p></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" =Ms&#111;normal><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><o:p>&nbsp;</o:p></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" =Ms&#111;normal><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>company.EntityAspect.AddToManager();<o:p></o:p></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" =Ms&#111;normal><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">return</SPAN> company;<o:p></o:p></SPAN></P><P style="LINE-HEIGHT: normal; MARGIN: 0in 0in 0pt; mso-layout-grid-align: n&#111;ne" =Ms&#111;normal><SPAN style="FONT-FAMILY: C&#111;nsolas; FONT-SIZE: 9.5pt"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}<o:p></o:p></SPAN></P><P style="MARGIN: 0in 0in 10pt" =Ms&#111;normal><o:p><FONT size=3 face=Calibri>&nbsp;</FONT></o:p></P><P style="MARGIN: 0in 0in 10pt" =Ms&#111;normal><FONT size=3><FONT face=Calibri>If we create a Company object as part of the Contact creation, how do we know <I style="mso-bidi-font-style: normal">not</I> to save it when it has no Name value?<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>I have considered calling Company.EntityAspect. AcceptChanges() as part of my Contact Create method and implementing logic in a Saving event handler to call SetAdded as necessary, but that creates a problem since Contact.CompanyId now has a value with no corresponding Company record.<o:p></o:p></FONT></FONT></P><P style="MARGIN: 0in 0in 10pt" =Ms&#111;normal><FONT size=3><FONT face=Calibri>I would expect this type of&nbsp;situation to arise frequently when dealing with non-trivial binding scenarios, so I am looking for a broadly applicable technique.<o:p></o:p></FONT></FONT></P><P style="MARGIN: 0in 0in 10pt" =Ms&#111;normal><FONT size=3><FONT face=Calibri>Thanks for your help.<o:p></o:p></FONT></FONT></P>]]>
   </description>
   <pubDate>Wed, 21 Apr 2010 20:50:04 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1741&amp;PID=6598#6598</guid>
  </item> 
 </channel>
</rss>