I’m sure most people ask why things don’t work. I am goIng to mix it up by asking why this does work.
private SmokeFireDBEntities dbContext = null;
private IList<MemberResponse> gridData = new List<MemberResponse>();
private void UserControl_Initialized(object sender, EventArgs e)
{
this.dbContext = new SmokeFireDBEntities();
var members = from m in dbContext.Members
where new[] { "A", "P", "S", "J" }.Contains(m.Class.ShortName)
orderby m.Line
select m;
foreach (Member m in members)
{
MemberResponse mr = new MemberResponse();
mr.MemberID = m.ID;
mr.Member = m;
this.gridData.Add(mr);
}
PercentageGrid.ItemsSource = this.gridData;
}
private void SaveButton_Click(object sender, RoutedEventArgs e)
{
AlarmTotal at = new AlarmTotal();
at.Month = Convert.ToByte(this.MonthField.Text);
at.Year = Convert.ToInt16(this.YearField.Text);
at.NumAlarms = Convert.ToInt16(this.TotalAlarmsField.Text);
this.dbContext.AlarmTotals.AddObject(at);
this.dbContext.SaveChanges();
// WHY IS THE FOLLOWING CODE NOT NECESSARY???
//foreach (MemberResponse mr in this.PercentageGrid.Items)
//{
// mr.AlarmTotalID = at.ID;
// this.dbContext.MemberResponses.AddObject(mr);
//}
//this.dbContext.SaveChanges();
}
<UserControl.Resources>
<DataTemplate x:Key="NameColumnTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Member.LastName}" />
<TextBlock Text=", " />
<TextBlock Text="{Binding Path=Member.FirstName}" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="InputColumnTemplate">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding Path=NumAttended}" Name="MonthResponse" Width="60" />
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<Grid Background="WhiteSmoke" Height="353" Width="509">
<TextBox Height="23" HorizontalAlignment="Left" Margin="12,33,0,0" Name="MonthField" VerticalAlignment="Top" Width="75" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="93,33,0,0" Name="YearField" VerticalAlignment="Top" Width="59" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="158,33,0,0" Name="TotalAlarmsField" VerticalAlignment="Top" Width="115" />
<ListView Margin="1,67,0,0" Name="PercentageGrid" ItemsSource="Binding" HorizontalAlignment="Stretch" Width="507" Height="286" VerticalAlignment="Stretch">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Name" CellTemplate="{StaticResource NameColumnTemplate}" />
<GridViewColumn Header="Line#" DisplayMemberBinding="{Binding Path=Member.Line}" />
<GridViewColumn Header="Class" DisplayMemberBinding="{Binding Path=Member.Class.ShortName}" />
<GridViewColumn Header="Response" CellTemplate="{StaticResource InputColumnTemplate}" />
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
I have removed unnecessary code to shorten this a bit. I am completely new to C#, .NET and everything that goes with it. I am completely stumped as to why this works at all. When I call the first dbContext.SaveChanges() to save the record to “AlarmTotals” it also saves all the “MemberResponse” records at the same time, and even more amazingly has the correct AlarmTotals.ID field populated. This one is really throwing me off, I just can’t understand how this works seemingly by magic.
Any insight and explaination would be greatly appreciated. I really want to understand what is going on here.
To add to what others said, I guess that the “magic” happens in the line 5:
This is the line that causes your new MemberResponse to attach to current EF ObjectContext (and subsequently, causes them to save on SaveChanges()). MemberResponse.Member is a EF navigation property.
But are you sure that saved MemberResponses have MemberResponse.AlarmTotalID set correctly? The code doesn’t look like it is. The best way to understand what really happened is to put a breakpoint in the setter of AlarmTotalID property.