Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Answering my own question in <strong>Part 2</strong>:</p> <p>Here is my approach to checking for related dependents when deleting an entity on the principal end of a many-to-one relationship and where dependents are NOT exposed as a navigation collection in the principal (e.g. class <code>Address</code> has a <code>Country</code> property, but class <code>Country</code> doesn't have an <code>Addresses</code> collection).</p> <p><em>DbContext</em></p> <p>Add the following method to the context class:</p> <pre><code>/// &lt;summary&gt; /// Returns an array of entities tracked by the /// context that satisfy the filter criteria. /// &lt;/summary&gt; public DbEntityEntry[] GetTrackedEntities&lt;T&gt;( Expression&lt;Func&lt;DbEntityEntry&lt;T&gt;, bool&gt;&gt; filterCriteria) where T : class { var result = new List&lt;DbEntityEntry&gt;(); var doesItMatch = filterCriteria.Compile(); foreach (var entry in this.ChangeTracker.Entries&lt;T&gt;()) { if (doesItMatch(entry)) result.Add(entry); } return result.ToArray(); } </code></pre> <p><em>Repositories</em></p> <p>Create a repository for each class that has some dependencies, override the <code>Delete</code> method and use the new <code>GetTrackedEntities&lt;T&gt;</code> method to get all related dependents and either:</p> <ul> <li>explicitly delete them if they are cascade-deletable in code</li> <li>detach them from the context if they are cascade-deletable in the DB itself</li> <li>throw an exception if they are NOT cascade-deletable. </li> </ul> <p>Example of the latter case:</p> <pre><code>public class EFCountryRepository : EFReadWriteRepository&lt;Country, string&gt;, ICountryRepository { public override void Delete(Country instance) { // Allow the Country to be deleted only if there are no dependent entities // currently in the context that are NOT cascade-deletable. if ( // are there any Regions in the context that belong to this Country? _dbContext.GetTrackedEntities&lt;Region&gt;(e =&gt; e.Entity.CountryID == instance.ID || e.Entity.Country == instance).Length &gt; 0 || // are there any Addresses in the context that belong to this Country? _dbContext.GetTrackedEntities&lt;Address&gt;(e =&gt; e.Entity.CountryID == instance.ID || e.Entity.Country == instance).Length &gt; 0 ) throw new Exception(String.Format( "Country '{0}' is in use and cannot be deleted.", instance.ID)); base.Delete(instance); } // ... other methods ... } </code></pre> <p>Example of a case where cascade-deleting will be done by the DB itself, so all we need to do is detach the dependents from the context:</p> <pre><code>public class EFOrderRepository : EFReadWriteRepository&lt;Order, string&gt;, IOrderRepository { public override void Delete(Order instance) { foreach (var orderItem in _dbContext.GetTrackedEntities&lt;OrderItem&gt;(e =&gt; e.Entity.OrderID == instance.ID || e.Entity.Order == instance)) { _dbContext.Entry(orderItem).State = System.Data.EntityState.Detached; } base.Delete(instance); } // ... other methods ... } </code></pre> <p>Hope someone will find this solution helpful.</p>
 

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