0

I'm struggling with a sub table many to many relationship. EF6

Table1:

Id int
Name string

Table2:

Id int
ParentId int fk
ChildId int fk

Table2 has two links to Table1 in it - ChildId, and ParentId which are Foreign keyed to Id in Table1. Entity Framework will update the ParentId correctly when called, but updates the ChildId to the ParentId of the Table1 Id?

public partial class GeographicPolygon : IPublishingEntity
{       
    public GeographicPolygon()
    {            
        this.GeographicPolygonLinkParents = new HashSet<GeographicPolygonLink>();
        this.GeographicPolygonLinkChildren = new HashSet<GeographicPolygonLink>();
    }

    public int Id { get; set; }
    public System.Guid InternalId { get; set; }        
    public string Name { get; set; }        
        
    [InverseProperty("GeographicPolygonParent")] 
    public virtual ICollection<GeographicPolygonLink> GeographicPolygonLinkParents { get; set; }
    
    [InverseProperty("GeographicPolygonChild")] 
    public virtual ICollection<GeographicPolygonLink> GeographicPolygonLinkChildren { get; set; }
}

public partial class GeographicPolygonLink : IEntity
{        
    public int Id { get; set; }                
    public int ParentId { get; set; }
    public int ChildId { get; set; }        

    [ForeignKey("ChildId")] 
    public virtual GeographicPolygon GeographicPolygonChild { get; set; }

    [ForeignKey("ParentId")] 
    public virtual GeographicPolygon GeographicPolygonParent { get; set; }
}

The data being passed in.

{
  "Id": 3,
  "Name": "New GeoPoly 2",    
  "GeographicPolygonLinkChildren": [
    {
      "ParentId": 3,
      "ChildId": 10,
    },
    {
      "ParentId": 3,
      "ChildId": 11,
    }
  ]
}

The call to the update is:

var internalId = Guid.Parse(document.InternalId);
var existing = await context.Set<TTarget>().FirstOrDefaultAsync(x => x.InternalId == internalId);
if (existing == null)
{
    existing = new TTarget {CreatedDate = DateTime.Now};
    context.Set<TTarget>().Add(existing);
}

mapper.Map(document, existing);

await context.SaveChangesAsync();

I look at 'existing' before the update and the Id's are all correct. ChildId's 10 and 11.

After the SaveChangeAsync the database has:

ID   ParentId  ChildId
320  3         3
321  3         3

I cannot get the ChildId to update correctly even with the annotations.

In my model builder I have:

builder.EntitySet<GeographicPolygonModel>("GeographicPolygon");
builder.EntitySet<GeographicPolygonLinkModel>("GeographicPolygonLink");

My edmx has:

<EntityType Name="GeographicPolygon">
  <Key>
    <PropertyRef Name="Id" />
  </Key>
  <Property Name="Id" Type="Int32" Nullable="false" />          
  <Property Name="Name" Type="String" Nullable="false" />                    
  <NavigationProperty Name="GeographicPolygonLinkParents" Relationship="DataContext.fkGeographicPolygonLinkParentId_GeographicPolygon" FromRole="GeographicPolygon" ToRole="GeographicPolygonLink" />
  <NavigationProperty Name="GeographicPolygonLinkChildren" Relationship="DataContext.fkGeographicPolygonLinkChildId_GeographicPolygon" FromRole="GeographicPolygon" ToRole="GeographicPolygonLink" />
</EntityType>

I've looked and looked, but nothing I have tried has worked?

Any ideas please?

Peter B
  • 22,460
  • 5
  • 32
  • 69
AndMac
  • 19
  • 1
  • 2
    From [ask]: _"Write a title that summarizes the specific problem"_. Would you say that your title does that? – ProgrammingLlama Aug 04 '21 at 08:42
  • Perhaps using a placeholder might help, see: https://stackoverflow.com/questions/45409093/entity-framework-adding-existing-child-to-a-new-parent-on-a-many-to-many-relatio – Davemundo Aug 04 '21 at 15:11
  • ....or change your data model as per this discussion, or use Load() etc, see: https://stackoverflow.com/questions/1308158/how-does-entity-framework-work-with-recursive-hierarchies-include-seems-not-t – Davemundo Aug 04 '21 at 15:13
  • What happens in `mapper.Map` and what is the content of `existing` and its collections afterwards? – Gert Arnold Aug 04 '21 at 15:17
  • Also, you have an EDMX and the classes have data annotations? That doesn't compute. The classes you show are not the classes generated by the EDMX or you modified them manually. – Gert Arnold Aug 04 '21 at 15:20

1 Answers1

1

try to add navigation properties

public partial class GeographicPolygonLink : IEntity
{        
    public int Id { get; set; }                
    public int ParentId { get; set; }
    public int ChildId { get; set; }        

    
    [ForeignKey(nameof(ChildId))]
   [InverseProperty(nameof(GeographicPolygon.GeographicPolygonLinkChildren))]
    public virtual GeographicPolygon GeographicPolygonChild { get; set; }

    [ForeignKey(nameof(ParentId))]
    [InverseProperty(nameof(GeographicPolygon.GeographicPolygonLinkParents))]
    public virtual GeographicPolygon GeographicPolygonParent { get; set; }
}


public partial class GeographicPolygon : IPublishingEntity
{       
   ...... 
        
   
  [InverseProperty(nameof(GeographicPolygonLink.GeographicPolygonParent))]
    public virtual ICollection<GeographicPolygonLink> GeographicPolygonLinkParents { get; set; }
    
    [InverseProperty(nameof(GeographicPolygonLink.GeographicPolygonChild))] 
    public virtual ICollection<GeographicPolygonLink> GeographicPolygonLinkChildren { get; set; }
}
Serge
  • 40,935
  • 4
  • 18
  • 45
  • Tried that. No luck :( – AndMac Aug 04 '21 at 22:00
  • @AndMac What is the error? – Serge Aug 04 '21 at 22:00
  • There is no error, that's the thing. It just doesn't update the column with the correct data. No matter what I set the ChildId to. If I look at SQL profiler, I can see that the Insert statements both have 3 as the childId exec sp_executesql N'INSERT [dbo].[GeographicPolygonLink]([ParentId], [ChildId]) VALUES (@0, @1) SELECT [Id], [RecordVersion] FROM [dbo].[GeographicPolygonLink] WHERE @@ROWCOUNT > 0 AND [Id] = scope_identity()',N'@0 int,@1 int,@0=3,@1=3 – AndMac Aug 04 '21 at 22:51
  • It should be working now. You just have to repeat db migration after adding attributes – Serge Aug 04 '21 at 23:04