Entity Framework - Почему это работает? - PullRequest
3 голосов
/ 30 марта 2012

Я уверен, что большинство людей спрашивают, почему вещи не работают. Я собираюсь все перепутать, спросив, почему это работает.

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>

Я удалил ненужный код, чтобы немного его сократить. Я совершенно новичок в C #, .NET и все, что с этим связано. Я полностью озадачен тем, почему это работает вообще. Когда я вызываю первый dbContext.SaveChanges (), чтобы сохранить запись в «AlarmTotals», он также сохраняет все записи «MemberResponse» одновременно и, что еще более удивительно, заполняет правильное поле AlarmTotals.ID. Это действительно отталкивает меня, я просто не могу понять, как это работает, по-видимому, по волшебству.

Любое понимание и объяснение будет с благодарностью. Я действительно хочу понять, что здесь происходит.

Ответы [ 3 ]

4 голосов
/ 30 марта 2012

Прежде всего, ваш контекст данных не закрыт, и вы потеряете TON памяти / пропускной способности, если вы не закрываете соединения с контекстом базы данных. Пожалуйста, посмотрите на это.

Во-вторых, метод .SaveChanges() определит, какой правильный идентификатор назначать в зависимости от настроек базы данных. Если там нет определения, такого как auto-increment, то возможно, что эти идентификаторы не будут установлены правильно, и вы можете сохранить в тот же идентификатор, а затем вызвать исключение. Внешним ключам детей будут назначаться только явные ассоциации, которые вы уже делаете.

Edit:

В ответ на ваш комментарий обычно используется оператор using для управления контекстами, потому что это чистый код:

var members = new Members();
using( var context = new SmokeFireDBEntities())
{
 //use context how you would, i.e.
 members = from m in context.Members
             where new[] { "A", "P", "S", "J" }.Contains(m.Class.ShortName)
             orderby m.Line
             select m;
}//once this is hit the context is closed and you can feel safe about your connection

Если этот подход не работает с тем, как долго вы хотите открыть соединение, вы также можете вручную (хотя и не рекомендуется) закрывать соединение самостоятельно.

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;
this.dbContext.Dispose();//this will close the connection for you, and if you need it re-opened then either call new Entities() again or use the using statement
3 голосов
/ 30 марта 2012

Чтобы добавить к тому, что говорили другие, я думаю, что "магия" происходит в строке 5:

1 foreach (Member m in members)
2 {
3     MemberResponse mr = new MemberResponse();
4     mr.MemberID = m.ID;
5     mr.Member = m;
6     this.gridData.Add(mr);
7 }

Это строка, которая заставляет ваш новый MemberResponse присоединяться к текущему EF ObjectContext (и впоследствии заставляет их сохранять в SaveChanges ()). MemberResponse.Member - это свойство EF-навигации.

Но вы уверены, что для сохраненных MemberResponses правильно задан MemberResponse.AlarmTotalID? Код не выглядит так, как есть. Лучший способ понять, что на самом деле произошло, - установить точку останова в установщике свойства AlarmTotalID .

2 голосов
/ 30 марта 2012

Краткий ответ: это то, что делают Контекст и Сущности; они отслеживают все это, так что сохраняются обновления всего графа объектов.

Под графом объектов я подразумеваю «корневой» объект, с которым вы работаете, и любые связанные элементы, которые вы можете прикрепить, независимо от того, всегда ли вы понимаете, что это то, что вы делаете или нет.

Это это потрясающе!

РЕДАКТИРОВАТЬ: Я рекомендую прочитать отличную работу Джулии Лерман, если вы хотите больше узнать о Entity Framework. Это очень большая тема, но она того стоит. У нее есть каноническая книга под названием Entity Framework, столбец msdn, блог и т. Д.

Обратите внимание, что вопросы о книгах на самом деле не имеют отношения к теме, но я предлагаю это, потому что вы, кажется, плохо знакомы с EF.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...