title: EFCore - Key values being changed from C.Link to B.Link under implementation in a common abstract base class as A.Link
body: <p>In the interest of making some use of RSS and Atom syndication formats, ideally for application with .NET dependency injection in a Xamarin.Forms application, I've managed to implement a service framework for processing RSS and Atom XML. I'm working on the data storage features, at present.</p>
  <p>In an excerpt of the codebase, I've implemented the following for adding RssChannel and RssItem objects directly to the database. Through some runtime reflection on a static method of a database adapter class for Rss content, this code is eventually run within <code>OnModelCreating(ModelBuilder builder)</code></p>
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-html lang-html prettyprint-override"><code>builder.Entity&lt;RssChannel&gt;().HasKey(channel =&gt; channel.RssLink);
  builder.Entity&lt;RssChannel&gt;().HasMany(channel =&gt; channel.Items).WithOne(item =&gt; item.Channel);
  builder.Entity&lt;RssItem&gt;().HasKey(item =&gt; new { item.RssLink, item.ObjectDateString });</code></pre>
  </div>
  </div>
  </p>
  <p><code>RssChannel</code> and <code>RssItem</code> have been implemented, here, as deriving from an abstract base class <code>RssSyndicationObject</code>.</p>
  <p>For purposes of XML deserialization, this class <code>RssSyndicationObject</code> has provided the implementation and XML annotation support for the <code>RssLink</code> property. That property - with its XML annotations - would then be inherited to each implementation class, <code>RssChannel</code> and <code>RssItem</code>.</p>
  <p><code>RssItem</code> is then defined with a property, <code>Channel</code>, such that provides a back link to the <code>RssChannel</code> publishing the <code>RssItem</code>.</p>
  <p>While working on supporting that much in the model builder, I've encountered the following message under the codebase's implementation. It appears to indicate that the key value based on the set <code>{RssItem.RssLink, RssItem.ObjectDateString}</code> is being modified, such that the <code>RssItem.RssLink</code> is then replaced with the value of the <code>RssChannel.RssLink</code> for the <code>RssChannel</code> of each individual <code>RssItem</code>.</p>
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-html lang-html prettyprint-override"><code>      Context 'SqliteStorageContext' started tracking 'RssChannel' entity with key '{RssLink: https://www.npr.org/templates/story/story.php?storyId=2}'.
  dbug: Microsoft.EntityFrameworkCore.ChangeTracking[10806]
        Context 'SqliteStorageContext' started tracking 'RssChannelImage' entity with key '{Uri: https://media.npr.org/images/podcasts/primary/npr_generic_image_300.jpg?s=200}'.
  dbug: Microsoft.EntityFrameworkCore.ChangeTracking[10803]
        The foreign key property 'RssItem.RssLink' was detected as changed from 'https://www.npr.org/2021/01/25/960354929/in-tiny-kansas-town-pandemic-skeptics-abound-amid-false-information-and-politics' to 'https://www.npr.org/templates/story/story.php?storyId=2' for entity with key '{RssLink: https://www.npr.org/templates/story/story.php?storyId=2, ObjectDateString: Mon, 25 Jan 2021 13:49:00 GMT}'.
  dbug: Microsoft.EntityFrameworkCore.ChangeTracking[10806]
        Context 'SqliteStorageContext' started tracking 'RssItem' entity with key '{RssLink: https://www.npr.org/templates/story/story.php?storyId=2, ObjectDateString: Mon, 25 Jan 2021 13:49:00 GMT}'.
  dbug: Microsoft.EntityFrameworkCore.ChangeTracking[10803]
        The foreign key property 'RssItem.RssLink' was detected as changed from 'https://www.npr.org/2021/01/25/960465917/israel-secures-covid-19-vaccine-doses-by-agreeing-to-share-medical-data-on-israe' to 'https://www.npr.org/templates/story/story.php?storyId=2' for entity with key '{RssLink: https://www.npr.org/templates/story/story.php?storyId=2, ObjectDateString: Mon, 25 Jan 2021 13:16:18 GMT}'.
  dbug: Microsoft.EntityFrameworkCore.ChangeTracking[10806]
        Context 'SqliteStorageContext' started tracking 'RssItem' entity with key '{RssLink: https://www.npr.org/templates/story/story.php?storyId=2, ObjectDateString: Mon, 25 Jan 2021 13:16:18 GMT}'.
  dbug: Microsoft.EntityFrameworkCore.ChangeTracking[10803]</code></pre>
  </div>
  </div>
  </p>
  <p>This, then, becomes an error.</p>
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-html lang-html prettyprint-override"><code>fail: TheNamespace.SyndicationDataManagerService[0]
        Received exception for https://feeds.npr.org/2/rss.xml : OtherNamespace.ProviderFailureException: General error
         ---&gt; System.InvalidOperationException: The instance of entity type 'RssItem' cannot be tracked because another instance with the key value '{RssLink: https://www.npr.org/templates/story/story.php?storyId=2, ObjectDateString: Mon, 25 Jan 2021 13:16:00 GMT}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.
           at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.ThrowIdentityConflict(InternalEntityEntry entry)
           at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(TKey key, InternalEntityEntry entry, Boolean updateDuplicate)
           at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(TKey key, InternalEntityEntry entry)
           at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NullableKeyIdentityMap`1.Add(InternalEntityEntry entry)</code></pre>
  </div>
  </div>
  </p>
  <p>The URL being used in that key is from the <code>RssChannel.RssLink</code>, not the original <code>RssItem.RssLink</code>. This, and the matter of the key being changed during runtime - is there any way to address that without modifying the implementation of one or both of <code>RssChannel</code> and <code>RssItem</code>?</p>
  <p>Whatever may be causing the change indicated in the &quot;detected as changed&quot; messages, I don't believe it's from my own code.</p>
  <p>I'd like to be able to retain that shared implementation of the 'RssLink' property in <code>RssSyndicationObject</code>. Though I believe I've discovered a workaround for that much, in implementing each &quot;link&quot; property separately in those implementation classes, but there must be a way to address this with the fluent API, under the model builder?</p>
  <p>Any advice would be appreciated. I've looked at the documentation for EFCore and the traditional Entity Framework implementation. The only way I've discovered for addressing it - when storing values from those XML record classes directly in the database - is to change the implementation of those XML record classes.</p>
  <p>While I plan on implementing an adapter framework, in some later testing for this application, but I don't believe I've seen the last of this issue.</p>
  <p><em><strong>Update</strong></em></p>
  <p>Using the following as the key for the <code>RssChannel</code> - instead of only the <code>RssLink</code> of the <code>RssChannel</code>, as above - the issue now does not seem to occur. It may represent a workaround, at least?</p>
  <pre><code>builder.Entity&lt;RssChannel&gt;().HasKey(channel =&gt; new { channel.RssLink, channel.RssTitle });
  </code></pre>
  <p>Albeit, this may not serve to address why the issue was occurring - such as to a question, Why was the <code>RssItem</code> key value being modified during runtime? such that after the key was already initialized, it would then be changed to use the <code>RssLink</code> of the item's containing channel. Looking at the code, I cannot imagine how that becomes an outcome for the key of any <code>RssItem</code>, when using only the channel's <code>RssLink</code> as a single-item key for each <code>RssChannel</code>.</p>
  <p>The matter of <code>RssChannel</code> and <code>RssItem</code> deriving from a similar base class was only a guess.</p>
  <p>At least, there might be a guess here, as towards one approach for a workaround about it, without modifying the implementation of the XML data classes?</p>
  <p><em><strong>Further Details</strong></em></p>
  <p>An excerpt of the codebase, under its present state of refactoring.</p>
  <pre><code>public abstract class SyndicationObject
  {
          [XmlIgnore]
          public string? ObjectTitle { get; set; }
  
          [XmlIgnore]
          public string? ObjectDateString { get; set; } 
          // ObjectDateString definition truncated. 
          // this property accesses a naïve ObjectDate property of type DateTime?
  }
  
  public abstract class RssSyndicationObject : SyndicationObject 
  {
          [XmlElement(&quot;link&quot;, Namespace = RssConstants.NsUriRss)]
          public string? RssLink { get; set; }
  
          [XmlElement(&quot;title&quot;, Namespace = RssConstants.NsUriRss)]
          public string? RssTitle { get =&gt; ObjectTitle; set =&gt; ObjectTitle = value; } 
  }
  
  
  public class RssItem : RssSyndicationObject
  {
          protected RssChannel? channel;
  
          [XmlIgnore]
          public RssChannel? Channel { get =&gt; channel; set =&gt; channel = value; }
  }
  
  
  public class RssChannel : RssSyndicationObject
  {
          [XmlElement(&quot;item&quot;, Namespace = RssConstants.NsUriRss)]
          public ItemsList&lt;RssChannel, RssItem&gt;? Items [...] 
          // Items property definition truncated for brevity.
          // This property sets the containing RssChannel on each RssItem
          // then stores the provided ItemsList&lt;RssChannel,RssItem&gt; under 
          // a protected field of the same type. 
          //
          // Later item-&gt; channel registration is provided in the
          // ItemsList&lt;T1,T2&gt;.Add(...) implementation, such that may
          // appear to be used under XML deserialization for this property
  }
  
  
  public class ItemsList&lt;TChannel, TItem&gt; : List&lt;TItem&gt; 
          where TChannel : RssChannel
          where TItem : RssItem
  {
  
          private TChannel rssChannel;
  
          public ItemsList(TChannel rssChannel) : base()
          {
              this.rssChannel = rssChannel;
          }
  
          new public void Add(TItem item)
          {
              base.Add(item);
              item.Channel = rssChannel;
          }
  }
  </code></pre>
  <p>Albeit unrelated to this issue, I'd been using an RssItem[]? type for storage of the channel items set. This worked out, insofar as for XML deserialization. However, this property could not be processed by the database adapter. While the <code>ItemsList&lt;..&gt;</code> implementation - in the revision presented here - may be naive, it providing no sorting or other functionality, it has at least served a role during the testing for data storage.</p>
  <p>Under some earlier refactoring about this issue, in trying out a redesign of the <code>RssItem</code> and <code>RssChannel</code> link properties, this issue had stopped occurring when I'd defined e.g <code>string? RssItem.ItemLink</code> and <code>string? RssChannel.ChannelLink</code> properties each stored in a field local to the class, rather than using the common <code>RssLink</code> property from <code>RssSyndicationObject</code>, in both of those implementation classes.</p>