I am currently having difficulty tracking and adding a parent-entity object to my context after successfully adding its related child.
I have two SQL tables mapped to my entities that are related by a foreign key:
MasterPartNumber (parent, one) --> MasterPartsList (children, many)
(PK) pn <--short for PartNumber (PK) listID
pnDesc (FK) pn
docNum parentAssyPN <-- if null, means it is the "top level assembly"
findNum
qty
isAssy
On the left hand side of my view, I have a ListBox that displays an ObservableCollection
of all the assembly, or parent entity objects. It looks like:
public ObservableCollection<MasterPartNumber> AssyPns
{
get
{
var enumerable = this._context.MasterPartNumbers.Where(x => x.isAssy == true);
return this._assyPns = new ObservableCollection<MasterPartNumber>(enumerable);
}
set
{
this._assyPns = value;
RaisePropertyChanged("AssyPns");
}
}
The Selected Parent Assembly is defined by the viewmodel property:
public MasterPartNumber SelectedTopLevelAssyPN
{
get { return this._selectedTopLevelAssyPN; }
set
{
this._selectedTopLevelAssyPN = value;
RaisePropertyChanged("SelectedTopLevelAssyPN");
RaisePropertyChanged("SelectedAssyBOMLineItems");
}
}
When a user clicks on one of the selected parent assembly (SelectedTopLevelAssyPN
), a DataGrid displays the ObservableCollection
bound to all the child entities whose parent (given by the property parentAssyPN
) is the SelectedTopLevelAssyPN
.
public ObservableCollection<MasterPartsList> SelectedAssyBOMLineItems
{
get
{
if (this._selectedTopLevelAssyPN != null)
{
var children = _context.MasterPartsLists.Where(lineItem => lineItem.parentAssyPN == this._selectedTopLevelAssyPN.pn);
return this._selectedAssyBOMLineItems = new ObservableCollection<MasterPartsList>(children);
}
return this._selectedAssyBOMLineItems;
}
set
{
this._selectedAssyBOMLineItems = value;
RaisePropertyChanged("SelectedAssyBOMLineItems");
}
}
Notice how I am able to navigate through collection properties down to the entity that contains the foreign key (here is my xaml):
<DataGrid x:Name="lineItemDataEntryGrid" Grid.Row="0"
Margin="15,15,15,0"
AutoGenerateColumns="False"
EnableRowVirtualization="True"
Width="Auto"
ItemsSource="{Binding SelectedAssyBOMLineItems, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
>
<DataGrid.Columns>
<DataGridTextColumn x:Name="qtyReadColumn"
Binding="{Binding qty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Width="SizeToHeader"
Header="QTY REQ'D"/>
<DataGridTextColumn x:Name="partOrIDNumColumn"
Binding="{Binding pn, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Width="SizeToHeader"
Header="PART OR IDENTIFYING NUMBER"/>
<DataGridTextColumn x:Name="partNumDescColumn"
Binding="{Binding MasterPartNumber.pnDesc, Mode= TwoWay, UpdateSourceTrigger=PropertyChanged}"
Width="SizeToHeader"
Header="NOMENCALTURE OR DESCRIPTION"/>
<DataGridTextColumn x:Name="docNumColumn"
Binding="{Binding MasterPartNumber.docNum, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Width="SizeToHeader"
Header="INTERNAL DOCUMENTATION"/>
<DataGridTemplateColumn x:Name="isAssyColumn"
Header="IS ASSEMBLY? "
Width="30"
>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding isAssy}" IsThreeState="False" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
And everything is displayed properly. That means I am effectively navigating down my parent entity to the child entity.
Now my problem: I am fully able to add the new items from MasterPartsList
to the context
, but not the MasterPartNumber
objects.
The code in my SaveCommand (Relay Command) looks like:
private void SaveLineItems()
{
//update the parts list if any Object properties have been edited
foreach (MasterPartsList item in this._selectedAssyBOMLineItems)
{
this._context.DetectChanges();
this._context.MasterPartsLists.AddObject(item);
// this._context.MasterPartNumbers.AddObject(item.MasterPartNumber); //Doesn't work: pnMatch.MasterPartNumber is null & Throws NullReferenceException
this._context.SaveChanges();
}
}
It appears that this would actually save my MasterPartsList data, if it weren't for the enforced foreign key constraint on MasterPartNumber.pn
which can't be null.
I have been stuck on this for days. I was so easily able to implement .SaveChanges when I was just working with one table. Is anyone able to see why I am unable to add item.MasterPartNumber
(or even get a non null object, for that matter?)
Thanks in advance. Please let me know where I need further clarification.