I have an application (.NET Framework 4.8) that uses Entity Framework Core 3.1.5. (I haven't dared to upgrade because I feel that this may break other dependencies - I'm glad it's working as it is.)
I am using a "Code First" approach to export data from SharePoint into SQL tables. Some SharePoint "lists" (SharePoint concept of tables) can contain M:N mappings, which I have to separate out into individual SQL tables.
Some code:
// Base class for all parent tables
internal abstract class SharePointListModel
{
[SharePointColumn("ID")]
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
public virtual void PostProcess()
{
}
}
// Base class for all child tables
internal abstract class AdditionalTableModel
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
}
// This is the child table, which is never inserted
[Table("MyMappingTable", Schema = "myschema")]
internal class MyMappingTable : AdditionalTableModel
{
// This points to a third table, but it could really
// be any value. It could also be a string or BLOB etc.
public int OtherTableId { get; set; }
}
// This is the parent table, which is inserted correctly
[Table("MySharePointTable", Schema = "myschema")]
internal class MySharePointTable : SharePointListModel
{
[SharePointColumn("SharePointLookupColumn", UseId = true)]
[NotMapped]
public int[] OtherTableIds { get; set; }
public List<MyMappingTable> Mappings { get; set; } // Making the property virtual doesn't change anything either
public override void PostProcess()
{
Mappings = OtherTableIds?.Select(x => new MyMappingTable { OtherTableId = x }).ToList();
}
}
Entity Framework seems to understand this, as dbContext.CreateTable() creates a table "MyMappingTable" that contains three columns (although only two properties are defined): Id, OtherTableId (actually a foreign key, but EF doesn't know that) and MySharePointTableId (foreign key).
But when I insert data like this, the M:N mapping table (MyMappingTable) remains empty:
IList<MySharePointTable> = LoadSharePointTable();
dbContext.AddRange(data);
dbContext.SaveChanges();
Explicitly mapping the parent doesn't help either:
[Table("MyMappingTable", Schema = "myschema")]
internal class MyMappingTable : AdditionalTableModel
{
public virtual MySharePointTable Parent { get; set; }
public int OtherTableId { get; set; }
}
// [...]
public override void PostProcess()
{
Mappings = OtherTableIds?.Select(x => new MyMappingTable { Parent = this, OtherTableId = x }).ToList();
}
I have also tried explicitly inserting the dependent rows, but that doesn't change anything:
IList<MySharePointTable> = LoadSharePointTable();
dbContext.AddRange(data);
IEnumerable<MyMappingTable> dependentRows = data.SelectMany(x => x.Mappings ?? Enumerable.Empty<MyMappingTable>());
dbContext.AddRange(dependentRows);
dbContext.SaveChanges();
Or like this, but this also doesn't change anything, the child table remains empty:
IList<MySharePointTable> = LoadSharePointTable();
dbContext.AddRange(data);
IEnumerable<MyMappingTable> dependentRows = data.SelectMany(x => x.Mappings ?? Enumerable.Empty<MyMappingTable>());
dbContext.Set<MyMappingTable>().AddRange(dependentRows);
dbContext.SaveChanges();
The insertion code is slightly simplified here as I'm actually using reflection for a generic approach, but I don't think that should matter.
What am I doing wrong?
CodePudding user response:
Just to be sure, aren't these two names suppose to match? Because everything seems correct, you should not need explicit insertion for the child entity EF should handle it.
CodePudding user response:
D'uh. It seems like I was looking at the wrong database the whole time...