Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Figured it out - wasn't easy, so i'll try to explain best i can. (for those who care)</p> <p><strong>Controller Relevant Code:</strong></p> <pre><code>// _userContentService is IUserContentService _userContentService.Update(review); </code></pre> <p>So, my controller calls a method called <code>Update</code> on <code>IUserContentService</code>, passing through the strongly-typed <code>Review</code> object.</p> <p><strong>User Content Service Relevant Code</strong></p> <pre><code>public void Update(Post post) { // _userContentRepository is IPostRepository _userContentRepository.UpdateModel(post); } </code></pre> <p>So, my service calls a method called <code>UpdateModel</code> on <code>IPostRepository</code>, passing through the strongly-typed <code>Review</code> object.</p> <p>Now, here is the tricky part.</p> <p>I actually have <strong>no specific Repositories</strong>. I have a <em>generic repository</em> called <code>GenericRepository&lt;T&gt; : IRepository&lt;T&gt;</code>, which handles <strong>all the different repositories.</strong></p> <p>So when something requests a <code>IPostRepository</code> (which my service was doing), DI would give it a <code>GenericRepository&lt;Post&gt;</code>.</p> <p>But now, i give it a <code>PostRepository</code>:</p> <pre><code>public class PostRepository : GenericRepository&lt;Post&gt;, IPostRepository { public void UpdateModel(Post post) { var originalPost = CurrentEntitySet.SingleOrDefault(p =&gt; p.PostId == post.PostId); Context.ApplyCurrentValues(GetEntityName&lt;Post&gt;(), post); } } </code></pre> <p>And because the class <em>derives</em> from <strong>GenericRepository</strong>, it inherits all the core repository logic (Find, Add, etc).</p> <p>At first, i tried to put that <strong>UpdateModel</strong> code in the <strong>GenericRepository</strong> class itself (and then i wouldn't have needed this specific repository), but the problem is the logic to retrieve the existing entity is based on a specific entity key, which the <code>GenericRepository&lt;T&gt;</code> would not know about.</p> <p>But the end result is the <em>stitching</em> is hidden deep down in the depths of the data layer, and i end up with a really clean Controller.</p> <p><strong>EDIT</strong></p> <p>This "stub technique" also works:</p> <pre><code>public void UpdateModel(Post post) { var stub = new Review {PostId = post.PostId}; CurrentEntitySet.Attach(stub); Context.ApplyCurrentValues(GetEntityName&lt;Post&gt;(), post); } </code></pre> <p>But the problem is because <strong>Post</strong> is abstract, i cannot instantiate and therefore would have to check the type of Post and create stubs for <em>every single</em> derived type. Not really an option.</p> <p><strong>EDIT 2 (LAST TIME)</strong></p> <p>Okay, got the "stub technique" working with abstract classes, so now the concurrency issue is solved.</p> <p>I added a generic type parameter to my <strong>UpdateModel</strong> method, and the special <strong><a href="http://msdn.microsoft.com/en-us/library/sd2w2ew5(VS.80).aspx" rel="nofollow noreferrer">new() constraint</a></strong>.</p> <p><strong>Implementation:</strong></p> <pre><code>public void UpdateModel&lt;T&gt;(T post) where T : Post, new() { var stub = new T { PostId = post.PostId }; CurrentEntitySet.Attach(stub); Context.ApplyCurrentValues(GetEntityName&lt;Post&gt;, post); } </code></pre> <p><strong>Interface:</strong></p> <pre><code>void UpdateModel&lt;T&gt;(T post) where T : Post, new(); </code></pre> <p>This prevents me from having to figure out the type of T manually, prevents concurrency issues and also prevents an extra trip to the DB.</p> <p>Pretty groovy.</p> <p><strong>EDIT 3 (i thought the last time was the last time)</strong></p> <p>The above "stub technique" works, but if i retrieve the object beforehand, it throws an exception stating an entity with that key already exists in the OSM.</p> <p>Can anyone advise how to handle this?</p> <p><strong>EDIT 4 (OK - this is it!)</strong></p> <p>I found the solution, thanks to this SO answer: <a href="https://stackoverflow.com/questions/1715501/is-is-possible-to-check-if-an-object-is-already-attached-to-a-data-context-in-ent/1716109#1716109">Is is possible to check if an object is already attached to a data context in Entity Framework?</a></p> <p>I had tried to "check if the entity is attached" using the following code:</p> <pre><code>ObjectStateEntry entry; CurrentContext.ObjectStateManager.TryGetObjectStateEntry(entity, out entry); </code></pre> <p>But it always returned <strong>null</strong>, even through when i explored the OSM i could see my entity there with the same key.</p> <p>But this code works:</p> <pre><code>CurrentContext.ObjectStateManager.TryGetObjectStateEntry(CurrentContext.CreateEntityKey(CurrentContext.GetEntityName&lt;T&gt;(), entity), out entry) </code></pre> <p>Maybe because i'm using Pure POCO's, the OSM had trouble figuring out the entity key, who knows.</p> <p>Oh and one other thing i added - so that i don't have to add a specific repository for each entity, i created an attribute called "<strong>[EntityKey]</strong>" (public property attribute).</p> <p>All POCO's must have 1 public property decorated with that attribute, or i throw an exception in my repository module.</p> <p>So my generic repository then looks for this property in order to create/setup the stub.</p> <p>Yes - it uses reflection, but it's clever reflection (attribute-based) and i'm already using reflection for plularization of entity set names from T.</p> <p>Anyway, problem solved - all working fine now!</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload