<?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 : MVVM with DevForce</title>
  <link>http://www.ideablade.com/forum/</link>
  <description>This is an XML content feed of; DevForce Community Forum : DevForce 2010 : MVVM with DevForce</description>
  <pubDate>Tue, 21 Apr 2026 10:40:14 -700</pubDate>
  <lastBuildDate>Thu, 10 Jun 2010 11:02:02 -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=1752</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>MVVM with DevForce : In DF 6.0.3 (June 8, 2010) we...</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1752&amp;PID=7253#7253</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> 1752<br /><strong>Posted:</strong> 10-Jun-2010 at 11:02am<br /><br />In DF 6.0.3 (June 8, 2010) we simplified the syntax for setting the LoadStrategy of a navigation property <DIV><P style="PAGE-BREAK-AFTER: avoid; MARGIN: 8pt 0in 4pt 0.5in" ="Ms&#111;normal"><SPAN style="FONT-FAMILY: Courier; COLOR: #2b91af; FONT-SIZE: 11pt; mso-bidi-font-family: C&#111;nsolas"><FONT size=3 face="Courier New, Courier, mono"><strong>Customer</strong></FONT></SPAN><SPAN style="FONT-FAMILY: Courier; FONT-SIZE: 11pt; mso-bidi-font-family: C&#111;nsolas"><FONT face="Courier New, Courier, mono"><FONT size=3><strong>.<SPAN style="COLOR: #2b91af">PropertyMetadata</SPAN>.CustomerStatus</strong> <SPAN style="COLOR: green">// NavigationEntityProperty</SPAN><BR><SPAN style="mso-spacerun: yes">&nbsp;&nbsp; </SPAN><strong>.ReferenceStrategy = <SPAN style="COLOR: #2b91af">EntityReferenceStrategy</SPAN>.NoLoad</strong>;</FONT></FONT></SPAN><SPAN style="FONT-FAMILY: C&#111;nsolas; COLOR: green; FONT-SIZE: 12pt"><?: prefix = o ns = "urn:schemas-microsoft-com:office:office" /><O:P></O:P></SPAN></P></DIV><DIV>Realize that this changes the load behavior "globally" ... meaning ...&nbsp;for that navigation property everywhere in the AppDomain.</DIV>]]>
   </description>
   <pubDate>Thu, 10 Jun 2010 11:02:02 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1752&amp;PID=7253#7253</guid>
  </item> 
  <item>
   <title>MVVM with DevForce : thanks  </title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1752&amp;PID=6742#6742</link>
   <description>
    <![CDATA[<strong>Author:</strong> <a href="http://www.ideablade.com/forum/member_profile.asp?PF=766" rel="nofollow">JerryHaskins</a><br /><strong>Subject:</strong> 1752<br /><strong>Posted:</strong> 30-Apr-2010 at 9:45am<br /><br />thanks]]>
   </description>
   <pubDate>Fri, 30 Apr 2010 09:45:37 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1752&amp;PID=6742#6742</guid>
  </item> 
  <item>
   <title>MVVM with DevForce : Great start! You definitely have...</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1752&amp;PID=6738#6738</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> 1752<br /><strong>Posted:</strong> 29-Apr-2010 at 7:45pm<br /><br />Great start! You definitely have the idea!<DIV>&nbsp;</DIV><DIV>I don't have time at this moment to dig in myself. Happy you are doing so :-)</DIV><DIV>&nbsp;</DIV><DIV>--</DIV><DIV>&nbsp;</DIV><DIV>You realize that you don't have to use the attribute approach. You can construct interceptors programmatically an add them directly to the PropertyInterceptorManager. You don't have to discover them.</DIV><DIV>&nbsp;</DIV><DIV>What you're doing is fine. Maybe it feels easier. Just want you to know about the direct way to add interceptors.</DIV><DIV>&nbsp;</DIV><DIV>--</DIV><DIV>&nbsp;</DIV><DIV>Why the &#091;AfterGet&#093;? Why not &#091;<strong>BeforeGet&#093;</strong>? </DIV><DIV>&nbsp;</DIV><DIV>Your interceptor can&nbsp;assign the args.Value as you do here and then you say "args.Cancel=true." That should stop further processing and the property should return "args.Value".<BR><BR>Thus your navigation property won't even attempt to get the value from the entity cache (as it does now) and you won't need&nbsp;guard logic to prevent the navigation from going to the server.<FONT face=C&#111;nsolas></DIV></FONT><DIV>You'll have to think about how to get the "referenceManager" to the interceptor. You can use an IoC to deliver it if you use IoC to construct your interception configuration class.</DIV><DIV>&nbsp;</DIV><DIV>Of course you WON'T USE A REFERENCEMANAGER. You will use a Reference Repository to get the CustomerStatus.&nbsp; The pertinent line in the interceptor should read something like:</DIV><DIV>&nbsp;</DIV><DIV><strong><SPAN ="n">&nbsp;&nbsp; args</SPAN><SPAN ="p">.</SPAN><SPAN ="n">Value</SPAN> <SPAN ="p">=</SPAN> <SPAN ="n">referenceRepository</SPAN><SPAN ="p">.Get</SPAN><SPAN ="n">CustomerStatusById(</SPAN> <SPAN ="p">(</SPAN><SPAN ="n">Guid</SPAN><SPAN ="p">)</SPAN><SPAN ="n">id</SPAN><SPAN ="p">);</SPAN></strong></DIV><DIV>&nbsp;</DIV><DIV>or perhaps you'll have a generic method</DIV><DIV>&nbsp;</DIV><DIV><strong>&nbsp;&nbsp;args<SPAN ="p">.</SPAN><SPAN ="n">Value</SPAN> <SPAN ="p">=</SPAN> <SPAN ="n">referenceRepository</SPAN><SPAN ="p">.Get</SPAN><SPAN ="n">ById&lt;CustomerStatus&gt;(<SPAN ="p">(</SPAN><SPAN ="n">Guid</SPAN><SPAN ="p">)</SPAN></SPAN><SPAN ="n">id</SPAN></strong><SPAN ="p"><strong>);</strong><DIV>&nbsp;</DIV><DIV>I realize yours is just a spike and you didn't have time for this refinement. But I feel strongly enough about this point that I don't want anyone reading this to miss it.</DIV><DIV>&nbsp;</DIV><DIV>Looking forward to hearing about your next move. </DIV><DIV>&nbsp;</DIV><DIV>The real test awaits. Will the idea hold up over time. Right now you have an auspicious beginning!</DIV><DIV>&nbsp;</DIV><DIV>--</DIV><DIV>&nbsp;</DIV><DIV><DIV><strong>Off&nbsp;on a Tangent:</strong> </DIV><DIV><DIV>&nbsp;</DIV><DIV>The following observation is independent of the work you're doing here. I thought of it only because you were striving to ensure that the navigation property never attempted to get the CustomerStatus from the server.</DIV><DIV>&nbsp;</DIV></DIV><DIV>You can configure a navigation property such that it ALWAYS looks in cache and NEVER goes to the server.</DIV><DIV>&nbsp;</DIV><DIV>For example, you could write:</DIV><DIV>&nbsp;</DIV><DIV><FONT face=C&#111;nsolas><FONT color=#2b91af>Customer</FONT>.<FONT color=#2b91af><FONT color=#2b91af>PropertyMetadata</FONT></FONT>.CustomerStatus.RelationLink.FromRole.ReferenceStrategy.LoadStrategy</FONT></DIV><DIV><FONT face=C&#111;nsolas>&nbsp; = <FONT color=#0000ff><FONT color=#0000ff>new</FONT></FONT> <FONT color=#2b91af><FONT color=#2b91af>EntityReferenceStrategy</FONT></FONT>(<FONT color=#2b91af><FONT color=#2b91af>EntityReferenceLoadStrategy</FONT></FONT>.<strong>DoNotLoad</strong>, <FONT color=#2b91af><FONT color=#2b91af>MergeStrategy</FONT></FONT>.PreserveChanges); <DIV><EM></EM>&nbsp;</DIV><DIV><FONT size=2 face="Arial, Helvetica, sans-serif">Not the most gracious syntax in the world (we may clean up a bit) but it does the trick.</FONT></DIV></FONT></DIV></DIV></SPAN></DIV>]]>
   </description>
   <pubDate>Thu, 29 Apr 2010 19:45:14 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1752&amp;PID=6738#6738</guid>
  </item> 
  <item>
   <title>MVVM with DevForce : OK. Here is a working example...</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1752&amp;PID=6726#6726</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> 1752<br /><strong>Posted:</strong> 29-Apr-2010 at 3:29pm<br /><br />OK. Here is a working example of #2, but it still needs some work.<br><br>Obviously this code is not perfect, and is just a simple illustration of how it could work.<br><br><pre><span ="k">using</span> <span ="nn">System</span><span ="p">;</span><br><span ="k">using</span> <span ="nn">System.Collections.Generic</span><span ="p">;</span><br><span ="k">using</span> <span ="nn">System.Linq</span><span ="p">;</span><br><span ="k">using</span> <span ="nn">System.Text</span><span ="p">;</span><br><span ="k">using</span> <span ="nn">DomainModel</span><span ="p">;</span><br><span ="k">using</span> <span ="nn">IdeaBlade.Core</span><span ="p">;</span><br><span ="k">using</span> <span ="nn">IdeaBlade.EntityModel</span><span ="p">;</span><br><br><span ="k">namespace</span> <span ="nn">DevForceInterceptorTest</span><br><span ="p">{</span><br>    <span ="k">class</span> <span ="nc">InterceptorTest</span><br>    <span ="p">{</span><br>        <span ="k">private</span> <span ="n">DomainModelEntityManager</span> <span ="n">customerManager</span><span ="p">;</span><br><br>        <span ="k">private</span> <span ="k">static</span> <span ="n">DomainModelEntityManager</span> <span ="n">referenceManager</span><span ="p">;</span><br>        <span ="k">private</span> <span ="k">static</span> <span ="n">IEnumerable</span><span ="p">&lt;</span><span ="n">Type</span><span ="p">&gt;</span> <span ="n">referenceTypes</span> <span ="p">=</span> <span ="k">new</span> <span ="n">Type</span><span ="p">&#091;&#093;</span> <span ="p">{</span> <span ="k">typeof</span><span ="p">(</span><span ="n">CustomerStatus</span><span ="p">)</span> <span ="p">};</span><br><br>        <span ="k">static</span> <span ="nf">InterceptorTest</span><span ="p">()</span><br>        <span ="p">{</span><br>            <span ="n">PropertyInterceptorManager</span><span ="p">.</span><span ="n">CurrentInstance</span><span ="p">.</span><span ="n">DiscoverInterceptorsFromAttributes</span><span ="p">(</span><span ="k">typeof</span><span ="p">(</span><span ="n">InterceptorTest</span><span ="p">));</span><br>            <span ="n">referenceManager</span> <span ="p">=</span> <span ="k">new</span> <span ="n">DomainModelEntityManager</span><span ="p">();</span><br>            <span ="n">referenceManager</span><span ="p">.</span><span ="n">CustomerStatuses</span><span ="p">.</span><span ="n">ToList</span><span ="p">();</span><br>        <span ="p">}</span><br><br>        <span ="k">public</span> <span ="k">void</span> <span ="nf">Start</span><span ="p">()</span><br>        <span ="p">{</span><br>            <span ="n">customerManager</span> <span ="p">=</span> <span ="k">new</span> <span ="n">DomainModelEntityManager</span><span ="p">();</span><br>            <span ="n">customerManager</span><span ="p">.</span><span ="n">DefaultQueryStrategy</span> <span ="p">=</span> <span ="n">QueryStrategy</span><span ="p">.</span><span ="n">CacheOnly</span><span ="p">;</span><br><br>            <span ="k">foreach</span> <span ="p">(</span><span ="n">Customer</span> <span ="n">customer</span> <span ="k">in</span> <span ="n">customerManager</span><span ="p">.</span><span ="n">Customers</span><span ="p">.</span><span ="n">With</span><span ="p">(</span><span ="n">QueryStrategy</span><span ="p">.</span><span ="n">DataSourceOnly</span><span ="p">).</span><span ="n">ToList</span><span ="p">())</span><br>            <span ="p">{</span><br>                <span ="n">Console</span><span ="p">.</span><span ="n">WriteLine</span><span ="p">(</span><span ="s">"Customer {0} Status {1}"</span><span ="p">,</span> <span ="n">customer</span><span ="p">.</span><span ="n">Name</span><span ="p">,</span> <span ="n">customer</span><span ="p">.</span><span ="n">CustomerStatus</span><span ="p">.</span><span ="n">Name</span><span ="p">);</span><br>            <span ="p">}</span><br><br>            <span ="n">Console</span><span ="p">.</span><span ="n">ReadKey</span><span ="p">();</span><br>        <span ="p">}</span><br><br><span ="na">        &#091;AfterGet(TargetType = typeof(TravelEntity))&#093;</span><br>        <span ="k">public</span> <span ="k">static</span> <span ="k">void</span> <span ="nf">ReferenceEntityGetInterceptor</span><span ="p">(</span><span ="n">IEntityPropertyInterceptorArgs</span> <span ="n">args</span><span ="p">)</span><br>        <span ="p">{</span><br>            <span ="k">if</span> <span ="p">(!</span><span ="n">referenceTypes</span><span ="p">.</span><span ="n">Contains</span><span ="p">(</span><span ="n">args</span><span ="p">.</span><span ="n">EntityProperty</span><span ="p">.</span><span ="n">DataType</span><span ="p">))</span><br>                <span ="k">return</span><span ="p">;</span><br><br>            <span ="n">NavigationEntityProperty</span> <span ="n">navigationProperty</span> <span ="p">=</span> <span ="p">(</span><span ="n">NavigationEntityProperty</span><span ="p">)</span><span ="n">args</span><span ="p">.</span><span ="n">EntityProperty</span><span ="p">;</span><br>            <span ="n">TravelEntity</span> <span ="n">entity</span> <span ="p">=</span> <span ="p">(</span><span ="n">TravelEntity</span><span ="p">)</span><span ="n">args</span><span ="p">.</span><span ="n">Instance</span><span ="p">;</span><br>            <span ="kt">string</span> <span ="n">fkName</span> <span ="p">=</span> <span ="n">navigationProperty</span><span ="p">.</span><span ="n">RelationLink</span><span ="p">.</span><span ="n">EntityRelation</span><span ="p">.</span><span ="n">Role1</span><span ="p">.</span><span ="n">Properties</span><span ="p">&#091;</span><span ="m">0</span><span ="p">&#093;.</span><span ="n">Name</span><span ="p">;</span><br>            <span ="kt">object</span> <span ="n">id</span> <span ="p">=</span> <span ="n">entity</span><span ="p">.</span><span ="n">EntityAspect</span><span ="p">&#091;</span><span ="n">fkName</span><span ="p">&#093;;</span><br><br>            <b><span ="k">if</span> <span ="p">(</span><span ="n">args</span><span ="p">.</span><span ="n">EntityProperty</span><span ="p">.</span><span ="n">DataType</span> <span ="p">==</span> <span ="k">typeof</span><span ="p">(</span><span ="n">CustomerStatus</span><span ="p">))</span><br>            <span ="p">{</span><br>                <span ="n">args</span><span ="p">.</span><span ="n">Value</span> <span ="p">=</span> <span ="n">referenceManager</span><span ="p">.</span><span ="n">CustomerStatuses</span><span ="p">.</span><span ="n">Where</span><span ="p">(</span><span ="n">cs</span> <span ="p">=&gt;</span> <span ="n">cs</span><span ="p">.</span><span ="n">Id</span> <span ="p">==</span> <span ="p">(</span><span ="n">Guid</span><span ="p">)</span><span ="n">id</span><span ="p">).</span><span ="n">FirstOrNullEntity</span><span ="p">();</span><br>            <span ="p">}</span></b><br><br>        <span ="p">}</span><br>    <span ="p">}</span><br><span ="p">}</span><br><br>Now, this does work, but I have bolded the section that needs some improvement. I'll have a think about making this more generic.<br><br><br></pre><br>]]>
   </description>
   <pubDate>Thu, 29 Apr 2010 15:29:38 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1752&amp;PID=6726#6726</guid>
  </item> 
  <item>
   <title>MVVM with DevForce :  That certainly gives me a lot...</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1752&amp;PID=6724#6724</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> 1752<br /><strong>Posted:</strong> 29-Apr-2010 at 2:15pm<br /><br />That certainly gives me a lot to think about :)<br><br>In regards to your Reference Strategy 2, I have a few thoughts on this.<br><br>Obviously you wouldn't want to add this complexity into your <b>DomainModel</b><br><br>Does DevForce look to other assemblies. for <b>Property Interceptors</b>? I believe it would, if we use the PropertyInterceptorManager's DiscoverInterceptorsFromAttributes method.<br><b><br></b>I have come up with two sample solutions for how we might accomplish this.<br><br><b>Solution 1: </b><br><br>&#091;BeforeGet(TargetType = typeof(Customer))&#093;<br>public static void CustomerStatusInterceptor(IEntityPropertyInterceptorArgs args)<br>{<br>&nbsp;&nbsp; if (args.EntityProperty.Name != EntityPropertyNames.Customer.CustomerStatus)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;<br><br>&nbsp;&nbsp; Customer cust = (Customer)args.Instance;<br><br>&nbsp;&nbsp; /*<br>Code here could be something such as:<br>&nbsp;&nbsp; args.value =&nbsp; ReferenceEntityManager.CustomerStatuses.Where(cs =&gt; cs.Id == cust.CustomerStatusId).FirstOrNullEntity();<br>you may want to delegate the query to an actual repository rather than keeping it here<br>*/<br>&nbsp;&nbsp; <br>}<br><br><b>Solution 2:</b> I'm not sure if this would work, but perhaps. Right now this code is assuming any entity that needs to be intercepted is of type BaseEntity.<br><br>&#091;BeforeGet(PropertyType = typeof(BaseEntity)&#093;<br>public static void ReferenceEntityGetInterceptor(IEntityPropertyInterceptorArgs args)<br>{<br>&nbsp;&nbsp; // From here we could either cast it to a NagivationEntityProperty, or do something with the EntityType <br><br>&nbsp;&nbsp;&nbsp; if (args.EntityProperty.EntityType == typeof(CustomerStatus))<br>&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>In here we would need some kind of generic way to find the foreign key field of whatever class wants this CustomerStatus, perhaps using the EntityRelationLink or some other method? This value would then be used to query it, the same way as above.<br>*/<br>&nbsp;&nbsp;&nbsp; }<br>}<br><br>Perhaps in example #2, you could have a list of&nbsp; "Intercepted" types, and in your Get Interceptor you could check to see if you are requesting one of these types.<br><br>Now, this would have to be done well, or I could see performance being impacted greatly.<br><br>If I get time, I'll try to do up such a sample project.<br><br>Thanks for the ideas!!<br><br><span style="font-size:10px"><br /><br />Edited by smi-mark - 29-Apr-2010 at 2:16pm</span>]]>
   </description>
   <pubDate>Thu, 29 Apr 2010 14:15:16 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1752&amp;PID=6724#6724</guid>
  </item> 
  <item>
   <title>MVVM with DevForce : Thanks for drawing a clear picture...</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1752&amp;PID=6722#6722</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> 1752<br /><strong>Posted:</strong> 29-Apr-2010 at 1:19pm<br /><br /><P>Thanks for drawing a clear picture of your app and workflow ... it's one we can all recognize too.</P><DIV>I'm about to lead you down a road that is familiar to me. It's not the only road. It's just one I happen to know.</DIV><DIV>&nbsp;</DIV><DIV>The road is a little rough ... and there are forks. We'll proceed as best we can ... with the clear understanding, I trust, that I am "suggesting", not mandating, a way forward. In many spots I'm thinking out loud. You have been warned!</DIV><DIV>&nbsp;</DIV><DIV>I start where you started. I like having a read-only&nbsp;repository of reference entities. It needn't be "the main repository" ... it just has to be reachable everywhere.</DIV><DIV>&nbsp;</DIV><DIV>Each Customer session is in its own sandbox ... just as you explain. </DIV><DIV>&nbsp;</DIV><DIV>I find this easier to bring off if each session has its own child container within a hierarchical IoC container. Load into the child container those services (such as the Customer Repository) which are singletons-with-respect-to-the-customer-session. That way each customer session gets its own repository, EntityManager, etc. Meanwhile, the services shared across the application, such as the Reference Repository, are accessible through the parent container.</DIV><DIV>&nbsp;</DIV><DIV>Sounds like you want an Administration Module to update reference data such as "Airline".&nbsp; I wouldn't add or modify characteristics of an Airline within my Customer edit module. I wouldn't expect to be modifying Airline info very often and, I'm guessing, only certain users are authorized to do so.</DIV><DIV>&nbsp;</DIV><DIV>Same for "TravelPlan" if by that you mean a reference plan shared across the application; if it's the customer's own travel plan, that would be customer data ... maintained in the customer edit module ... and NOT stored in the Reference Repository.</DIV><DIV>&nbsp;</DIV><DIV>Given that the Reference Repository is read-only, the Admin Module does its own thing with its own EntityManager ... and you want it to communicate changes to reference entities in some way that causes the Reference Repository to be updated ... preferrable without it having to go to the database.</DIV><DIV>&nbsp;</DIV><DIV>For these and other reasons, you probably want&nbsp;a Reference&nbsp;<strong><U>module</U></strong> associated with your Reference Repository. That module is responsible for&nbsp;maintaining the read-only reference entities. It&nbsp;may be responsible for populating&nbsp;the&nbsp;EntityManagers of child repositories (see below).</DIV><DIV>&nbsp;</DIV><DIV>It can also provide list services for the entire application; consumers ask&nbsp;it for reference lists that populate comboboxes and such; it might even provide ready-made combobox controls that are easy to "bind" to the entities exposed in the UI.</DIV><DIV>&nbsp;</DIV><DIV>Your local user isn't the only one who might update Reference entities. Your Reference module could periodically, asynchronously, refresh its entities from the database. (I discuss consequences of this toward the end of this post).</DIV><BLOCKQUOTE style="MARGIN-RIGHT: 0px" dir=ltr><DIV>A proper discussion of how best&nbsp;to&nbsp;refresh the reference data&nbsp;from the database&nbsp;is out-of-scope; "best" is a function of too many factors to cover here. For now we'll assume you poll every ... I don't know ... couple of minutes. The point is that the polling frequency is too long to keep up with changes made by the local user. The local user will expect to see her changes propagated immediately.</DIV></BLOCKQUOTE><DIV>Therefore, as you suggest, the Reference Repository must be updated by some mechanism other than the slower, remote-refresh cycle and, preferably, without a trip to the server. The mechanics of transfering entities from the Admin Module (which saved the changes) to your Reference Repository are simple as you say: just import them using the EntityManager Import feature.</DIV><DIV>&nbsp;</DIV><DIV>The more interesting question is "how does the Reference Repository learn about the entities it should update?" In a simple - but tightly coupled approach - the Admin Module would pass the changed entities to the Reference Repository directly.</DIV><DIV>&nbsp;</DIV><DIV>It certainly has access to the Reference Repository. The Reference&nbsp;&nbsp;repository can provide a method that receives "updated entities". The caller doesn't have to know which entities to give to the Ref Repo; just give it everything you save ... and let the Ref Repo decide which of them it cares about!</DIV><DIV>&nbsp;</DIV><DIV>You might prefer a more decoupled approach; I know I would prefer a decoupled approach.&nbsp;When a module&nbsp;saves any entities successfully, instead of calling the Ref Repo, it "announces" this fact by publishing an "EntitiesSaved" message with the saved entities in the message payload. The Ref Repo listens for this message and does its thing ... just as if it had been called directly.</DIV><DIV>&nbsp;</DIV><DIV>You might consider putting the code to raise the message inside the EntityManager.Saved event. That encapsulates the concern nicely and minimizes the risk of forgetting to send the message.</DIV><DIV>&nbsp;</DIV><DIV>You could use an Event Aggregator as the message broker;&nbsp;many people would ... I would ... and there's an EA waiting for you in PRISM, MVVM Lite, and lots of other such frameworks. Or you could make an EntitySaveTracking service that is dedicated to propagating this message.</DIV><BLOCKQUOTE style="MARGIN-RIGHT: 0px" dir=ltr><DIV>Don't dismiss the messaging approach (whether you use an EA or a specialized service). You will have created a mechanism whereby any module&nbsp;can learn about entity saves coming from anywhere. You'll have something more general than just a way to alert the Ref Repo to such changes.</DIV></BLOCKQUOTE><DIV>I need to bring up one more issue. We've talked about how the Ref Repo learns of changes to reference entities.&nbsp;Now how will child Repositories learn of and&nbsp;respond to changes in the Reference Repository!</DIV><DIV>&nbsp;</DIV><DIV>The answer depends upon how child repositories ... or, more precisely, their EntityManagers ... are referring to the reference entities. You have (at least) two choices:</DIV><DIV>&nbsp;</DIV><DIV>1) Each child repository has&nbsp;a copy of the reference entities. The copies were imported from the Ref Repo when the child repository was created.</DIV><DIV>&nbsp;</DIV><DIV>2) Entities in child repositories don't use DevForce entity navigation to get to reference entities. They use some form of custom navigation path that leverages the Ref Repo and the entities in the Ref Repo's EntityManager!</DIV><DIV>&nbsp;</DIV><DIV>You proposed to adopt #1 so I'll defer discussion of #2 to an addendum to this post.</DIV><DIV>&nbsp;</DIV><DIV>Ok, with #1, you're willing to burn memory with copies of reference entities. This certainly makes entity navigations to the reference entities easy. You don't have to do a thing; Customer.CustomerStatus just works.</DIV><DIV>&nbsp;</DIV><DIV>However, when reference entities change in the Reference Repository, the child repositories are going to have stale ... incorrect copies. Follow me here:</DIV><UL><LI>Admin Module&nbsp;adds a new Airline</LI><LI>Admin Module changes the name of an existing Airline</LI><LI>Customer Edit session 'A' has Airline with the old name and doesn't know about the new Airline</LI><LI>Customer Edit session 'B' is in the same boat.</LI></UL><P>What do you do? You can't just fold the Admin Module into the Customer Edit Module ... because you won't have dealt with the real problem ... that other modules (session 'B' in this example) have stale Reference Entity state.</P><DIV>One approach is for each child module to be listening for those saved entities and to have logic to update their&nbsp;own copies of the reference entities. I think this is a terrible idea; it&nbsp;spreads repair logic all over the place.</DIV><DIV>&nbsp;</DIV><DIV>I'm thinking&nbsp;maybe the child&nbsp;Repositories&nbsp;listen for a message from the Ref Repo saying "I've got updates". They respond by&nbsp;asking the Ref Repo to refresh&nbsp;them ... in&nbsp;the same way they got their ref entities (and&nbsp;lists,&nbsp;etc.)&nbsp;the first time.&nbsp;I'm not sure about this though.&nbsp;I'll may to think about it more; I know that you&nbsp;will :-)&nbsp;</DIV><DIV>&nbsp;</DIV><DIV>I'm sure we've forgotten something :-)</DIV><DIV>&nbsp;</DIV><DIV><strong>Addendum: a note on Reference Strategy #2:</strong></DIV><DIV>&nbsp;</DIV><DIV>#2 doesn't have the problem of propagating reference entity changes to child repositories. The child repositories are actually using the entities resident within the Reference Repo; they are updated automagically.</DIV><DIV>&nbsp;</DIV><DIV>This is a huge advantage if you anticipate frequent changes to reference entities.</DIV><DIV>&nbsp;</DIV><DIV>However, you'll have to finagle things to make #2 work. With #2 you&nbsp;can't use Customer.CustomerStatus as DevForce constructs it&nbsp;... at least not if DevForce generated it in support of a&nbsp;Customer&lt;--&gt;CustomerStatus association in the EF model.&nbsp;</DIV><DIV>&nbsp;</DIV><DIV>You can't because the CustomerStatus navigation property will look for CustomerStatus in the same EntityManager as the Customer ... and its not there! It's sitting in a different EM ... the Ref Repo's EM.</DIV><DIV>&nbsp;</DIV><DIV>If you expect reference entity update to be rare, you'll probably prefer #1.&nbsp; Life is much simpler if you can treat reference data as immutable for the lifetime of a client session.</DIV><DIV>&nbsp;</DIV><DIV>Let's suppose reference entity updates are not rare.&nbsp; What can you do to make Customer.CustomerStatus reach for the CustomerStatus entity in the Ref Repo.</DIV><DIV>&nbsp;</DIV><DIV>You should be able to inject custom <strong>property interceptors</strong> into the navigation properties that trade in reference entities.&nbsp;An interceptor of Customer.CustomerStatus would re-route the get and set&nbsp;through the Ref Repo.</DIV><DIV>&nbsp;</DIV><DIV>I haven't explored this yet myself ... but it holds promise!</DIV>]]>
   </description>
   <pubDate>Thu, 29 Apr 2010 13:19:41 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1752&amp;PID=6722#6722</guid>
  </item> 
  <item>
   <title>MVVM with DevForce : Ward, thanks for taking the time...</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1752&amp;PID=6712#6712</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> 1752<br /><strong>Posted:</strong> 29-Apr-2010 at 7:27am<br /><br />Ward, thanks for taking the time to reply to me. Your insight is much appreciated :)<br><br>If we use your example of a Travel Agent, as the scenario, this is the way I envision it:<br><br>These are our entities:<br><br>Customer<br><br>CustomerTravelPlan<br><br>TravelPlan<br><br>Airline<br><br>When the application loads, we can PreQuery the lookup tables into our main repository, and when VM’s need them, they can use this repository to get the data they need, rather than each VM querying this data. I see this main repository, as being a read only repository, ie, no persistence actions performed upon it. Any actions, such as a save, will be performed in a separate sandbox, only upon a successful save, will data be merged back into the main repository.<br><br>If we need to create a new “Airline”, we could go into the appropriate screen, which would have its own repository. Upon saving this new Airline, this entity would then be merged back into the main repository, allowing any other screens that rely on this collection, to see it.<br><br>It is important that multiple customers, and multiple travel plans be editable at any one time. When we want to edit a customer, if we don’t have the information in our main repository, then we will go to the database and fetch all the relevant details, upon retrieving this data, it is then brought into our customer repository. Tables such as Airline and TravelPlan are not brought into our new repository, as they won’t be changed by our “unit of work”, they will simply be queried from the main repository.<br><br><br>For each customer we are working on, we will have a new instance of the repository.<br><br>If we are in the middle of creating a new customer, and we realize that a travel plan needs to be added or modified, we can simply create a new plan, and once it is saved, it will be merged back into our main repository, and our Customer screen will now see the change.<br><br>Much of this is new to me, but I believe I grasp the basic concepts of it. Talking about it can be a lot easier than implementing it though!<br><br>&nbsp;<br><br>If I have any of this wrong, please feel free to correct me!<br><br><br>Thanks,<br><br>&nbsp;<br><br>Mark<br><br><span style="font-size:10px"><br /><br />Edited by smi-mark - 29-Apr-2010 at 7:27am</span>]]>
   </description>
   <pubDate>Thu, 29 Apr 2010 07:27:28 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1752&amp;PID=6712#6712</guid>
  </item> 
  <item>
   <title>MVVM with DevForce : What I Know &amp;#034;For Sure&amp;#034;  I...</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1752&amp;PID=6710#6710</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> 1752<br /><strong>Posted:</strong> 28-Apr-2010 at 7:53pm<br /><br /><DIV><strong>What I Know "For Sure"</strong></DIV><DIV>&nbsp;</DIV><DIV>I strongly recommend encapsulating the EntityManager inside a helper class ... typically a Repository. </DIV><DIV>&nbsp;</DIV><DIV>I also strongly recommend building your application with a Inversion of Control (IoC) container. Prism today defaults to Unity but you can use anything you like.</DIV><DIV><DIV>&nbsp;</DIV><DIV>Following this lead, ViewModels that require persistence services expect the&nbsp;module-specific Repository to be injected.&nbsp;</DIV><DIV>&nbsp;</DIV><DIV>In most applications,&nbsp;the Module Repository is registed with the&nbsp;IoC container as a singleton (a "service") and the same Repository instance is injected to every ViewModel that needs it.</DIV></DIV><DIV>&nbsp;</DIV><DIV><strong>Sharing a Repository Among ViewModels of a Composite View</strong></DIV><DIV>&nbsp;</DIV><DIV>It's not clear to me that every VM in a composite view needs to be able to access the repository. </DIV><DIV>&nbsp;</DIV><DIV>The Account Maintenance Screen could be seen as the "mini-shell" for the workflow and its VM could be responsible for coordinating the VMs of the child views that make up the composed screen.</DIV><DIV>&nbsp;</DIV><DIV>In a "View Model First" implementation, this mini-shell VM could handle persistence chores for the child VMs through some linkage with them ... some parent-child, VM communication protocol of your devising. When the child VMs need entities or some kind of persistence operation, it makes a request to the parent ... this mini-shell VM.</DIV><DIV>&nbsp;</DIV><DIV>No child VM can go rogue and instigate un-coordinated persistence operations (such as premature saves). The mini-shell, parent VM is in charge of the important decisions for the entire&nbsp;"Account Maintenance Screen".</DIV><DIV>&nbsp;</DIV><DIV>But if you really want your&nbsp;the child VMs&nbsp;to have direct access to the repository and manage persistence operations on their own, you have two obvious choices.</DIV><DIV>&nbsp;</DIV><DIV>(1) The&nbsp;mini-shell VM can simply hand its repository to the child VMs as it is composing them.</DIV><DIV>&nbsp;</DIV><DIV>(2) Let the IoC inject the child VMs with the same singleton Repository it gave to the mini-shell VM.</DIV><DIV>&nbsp;</DIV><DIV>I wish I could pronounce "there is one and only one right way to do this."&nbsp; I just can't say that. But there are a few basic approaches and I hope the ones I've outlined here are helpful to you.</DIV><DIV>&nbsp;</DIV><DIV><strong>Some Views get the ONE REPOSITORY; others get their own.</strong></DIV><DIV>&nbsp;</DIV><DIV>Per my earlier remarks, no "View"&nbsp;or VM&nbsp;ever gets its own EntityManager. But what I think you mean is that you might spin up some ViewModels, each governing its own independent workflow, each with its own EM ... lurking somewhere ... to properly sandbox the changes.&nbsp;</DIV><DIV>&nbsp;</DIV><DIV>I cover one way to do that below. But in the simple case, you could register the Repository to be created anew each time instead of as a singleton service.</DIV><DIV>&nbsp;</DIV><DIV>If you need <strong>both</strong> approaches in the same module ... the Singleton Repository in most cases but an Instance Repository for other cases ... and, worse case, there is only one concrete Repository class for all cases ...&nbsp;I'd probably write a sub-class of this repository for, say, the&nbsp;Instance Repository case.</DIV><DIV>&nbsp;</DIV><DIV>Then I'd register the base-class repository as the Singleton and the sub-class repository for Instance creation.&nbsp;Each VM requests injection of the repository that is most appropriate.</DIV><DIV>&nbsp;</DIV><DIV>Note that the sub-class Repository probably differs from the Singleton Repository in asking for injection of an new EntityManager wrapper (see below) each time it is created.</DIV><DIV>&nbsp;</DIV><DIV><strong>Additonal Notes:</strong> </DIV><DIV>&nbsp;</DIV><DIV>A Repository can construct its own EntityManager but I don't like that. I want the Repository to obtain its EntityManager by injection as well.</DIV><DIV>&nbsp;</DIV><DIV>Typically an EM arrives in a wrapper class that has&nbsp;configured the EM "just right". This bit of indirection makes it much easier to use the Repository in light-weight integration tests. I&nbsp;can easily substitute a suitable&nbsp;Test Double for the production EM ... and the Repository is none the wiser.</DIV><DIV>&nbsp;</DIV><DIV>--</DIV><DIV>&nbsp;</DIV><DIV>Sometimes you need to have the same "workflow" in motion multiple times. Maybe you're a travel agent and you're working on two separate customer travel plans at the same time. You want the two workflows to be completely independent. You want two instances of the "Travel Management Screen" and workflow.&nbsp;</DIV><DIV>&nbsp;</DIV><DIV>The two workflows should have separate Entity Managers. </DIV><DIV>&nbsp;</DIV><DIV>In this situation, I often rely upon an IoC container that supports "container hierarchy"; Unity, MEF, and StructureMap all do so. </DIV><DIV>&nbsp;</DIV><DIV>That means that there is a master container when the&nbsp;application bootstraps. Then you create sub-containers for each independent workflow. You would create a separate "Travel Repository" as a singleton service in each sub-container such that each workflow gets its own Repository (and its own embedded EM).</DIV><DIV>&nbsp;</DIV><DIV><strong>Conclusion</strong></DIV><DIV>&nbsp;</DIV><DIV>I have the feeling this all sounds complicated. </DIV><DIV>&nbsp;</DIV><DIV>In my defense, you presented a complicated scenario. You mentioned ViewModels,&nbsp;composite&nbsp;screens,&nbsp;and PRISM and that suggests to me that you are looking for the kind of loosely coupled solutions I'm describing here.</DIV><DIV>&nbsp;</DIV><DIV>Once you have experience with IoC and VMs ... the apparent complexity fades into familiarity. You'll have to trust me on that; it really will seem like&nbsp;hum-drum application composition.</DIV><DIV>&nbsp;</DIV><DIV>Hope this helps.</DIV><DIV>&nbsp;</DIV>]]>
   </description>
   <pubDate>Wed, 28 Apr 2010 19:53:01 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1752&amp;PID=6710#6710</guid>
  </item> 
  <item>
   <title>MVVM with DevForce : When one is creating screens,...</title>
   <link>http://www.ideablade.com/forum/forum_posts.asp?TID=1752&amp;PID=6652#6652</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> 1752<br /><strong>Posted:</strong> 26-Apr-2010 at 10:54am<br /><br />When one is creating screens, composed of multiple views/VMs, what is the best way to share a persistence context between them?<br><br>If you have an account maintenance screen, with many views for all the supporting data, you would want several views to share the same EntityManager, but in some cases, you would want a single EM for a view.<br><br>Ward mentioned this in another post, and I was intrigued, having not yet delved too deeply into Prism.<br><br>Thanks!<br>]]>
   </description>
   <pubDate>Mon, 26 Apr 2010 10:54:59 -700</pubDate>
   <guid isPermaLink="true">http://www.ideablade.com/forum/forum_posts.asp?TID=1752&amp;PID=6652#6652</guid>
  </item> 
 </channel>
</rss>