Note that there are some explanatory texts on larger screens.

plurals
  1. POUpdating database record using Entity Framework (lazy loading and virtual properties)
    primarykey
    data
    text
    <p>I'm struggling with <em>updating</em> existing lecturer's data in database. <br /> Every lecturer has <strong>Name</strong>, <strong>AcademicDegree</strong> and <strong>Courses</strong> which are taught by him/her (<em>Courses==Lessons</em>). </p> <p>In fact there are more properties in <code>class Lecturer</code> but they are not relevant. For simplicity lets assume that <a href="http://en.wikipedia.org/wiki/Plain_Old_CLR_Object" rel="nofollow noreferrer">POCO</a> class is defined this way:</p> <pre class="lang-cs prettyprint-override"><code>// POCO class (Entity Framework Reverse Engineering Code First) public class Lecturer { public Lecturer() { this.Courses = new List&lt;Course&gt;(); } public int Id_Lecturer { get; set; } // Primary Key public string Name { get; set; } public int? Academic_Degree_Id { get; set; } public virtual AcademicDegree AcademicDegree { get; set; } public virtual ICollection&lt;Course&gt; Courses { get; set; } } </code></pre> <p>In <em>Data Access Layer</em> I have method <code>void UpdateLecturer(Lecturer lecturer)</code> which should update lecturer whose <code>Id_Lecturer</code> is equal to <code>lecturer.Id_Lecturer</code> (using <code>lecturer.Name</code>, <code>lecturer.AcademicDegree</code> and <code>lecturer.Courses</code>). </p> <p>It's very handy method because in <em>ViewModel</em> I can call <code>_dataAccess.UpdateLecturer(SelectedLecturer)</code> (where <code>SelectedLecturer</code> is binded in <a href="http://en.wikipedia.org/wiki/Extensible_Application_Markup_Language" rel="nofollow noreferrer">XAML</a>; <code>SelectedLecturer</code> properties can be set by user in <code>TextBox</code>es and <code>Checkbox</code>).</p> <p>Unfortunatelly this method:</p> <pre class="lang-cs prettyprint-override"><code> public void UpdateLecturer(Lecturer lecturer) { using(var db = new AcademicTimetableDbContext()) { // Find lecturer with Primary Key set to 'lecturer.Id_Lecturer': var lect = db.Lecturers.Find(lecturer.Id_Lecturer); // If not found: if (lect == null) return; // Copy all possible properties: db.Entry(lect).CurrentValues.SetValues(lecturer); // Everything was copied except 'Courses'. Why?! // I tried to add this, but it doesn't help: // var stateMgr = (db as IObjectContextAdapter).ObjectContext.ObjectStateManager; // var stateEntry = stateMgr.GetObjectStateEntry(lect); // stateEntry.SetModified(); db.SaveChanges(); } } </code></pre> <p>updates everything (i.e. <code>Id_Lecturer</code>, <code>Name</code>, <code>Academic_Degree_Id</code> and <code>AcademicDegree</code>) <strong>except</strong> <code>Courses</code> which are unchanged after <code>db.SaveChanges()</code>. </p> <p>Why? How can I fix it?</p> <hr> <p>Similar problems: </p> <ul> <li><a href="https://stackoverflow.com/questions/6655716/updating-an-entity-in-entity-framework">updating-an-entity-in-entity-framework</a></li> <li><a href="https://stackoverflow.com/questions/700192/how-do-can-i-attach-a-entity-framework-object-that-isnt-from-the-database">how-do-can-i-attach-a-entity-framework-object-that-isnt-from-the-database</a></li> <li><a href="http://blogs.msdn.com/b/adonet/archive/2011/01/29/using-dbcontext-in-ef-feature-ctp5-part-4-add-attach-and-entity-states.aspx" rel="nofollow noreferrer">using-dbcontext-in-ef-feature-ctp5-part-4-add-attach-and-entity-states.aspx</a></li> <li><a href="https://stackoverflow.com/questions/1612655/entity-framework-updating-with-related-entity">entity-framework-updating-with-related-entity</a></li> <li><a href="https://stackoverflow.com/questions/4168073/entity-framework-code-first-no-detach-method-on-dbcontext">entity-framework-code-first-no-detach-method-on-dbcontext</a></li> </ul> <hr> <p><em>-- Edit --</em></p> <p>I also tried this way (idea came from <a href="https://stackoverflow.com/questions/12585664/an-object-with-the-same-key-already-exists-in-the-objectstatemanager-the-object#12587752">this post</a>): </p> <pre class="lang-cs prettyprint-override"><code>public void UpdateLecturer(Lecturer lecturer) { using (var db = new AcademicTimetableDbContext()) { if (lecturer == null) return; DbEntityEntry&lt;Lecturer&gt; entry = db.Entry(lecturer); if (entry.State == EntityState.Detached) { Lecturer attachedEntity = db.Set&lt;Lecturer&gt;().Find(lecturer.Id_Lecturer); if (attachedEntity == null) entry.State = EntityState.Modified; else db.Entry(attachedEntity).CurrentValues.SetValues(lecturer); } db.SaveChanges(); } } </code></pre> <p>but still <em>Courses</em> don't overwrite old values.</p> <hr> <p>-- Edit 2 --</p> <p>In response to the @Slauma question I'll describe how I loaded <code>SelectedLecturer</code> (which is passed to <code>UpdateLecturer(Lecturer lecturer)</code> method as an argument). </p> <p>I'm implementing <a href="http://en.wikipedia.org/wiki/Model_View_ViewModel" rel="nofollow noreferrer">MVVM</a> concept so I have <em>View</em> project within my <em>Solution</em> with <code>DataContext</code> set to <code>LecturerListViewModel</code>. In <em>View</em> there is <code>DataGrid</code> with list of all lecturers fetched from databse. <code>DataGrid</code> is binded this way: </p> <pre class="lang-xml prettyprint-override"><code>&lt;DataGrid AutoGenerateColumns="False" Name="LecturersDataGrid" HeadersVisibility="Column" IsReadOnly="True" ItemsSource="{Binding Lecturers,Mode=TwoWay}" SelectedItem="{Binding SelectedLecturer, Mode=TwoWay}"&gt; &lt;DataGrid.Columns&gt; &lt;DataGridTextColumn Header="Name" Binding="{Binding Name}" /&gt; &lt;DataGridTextColumn Header="Academic degree" Binding="{Binding AcademicDegree.Degree_Name}" /&gt; &lt;DataGridTemplateColumn&gt; &lt;DataGridTemplateColumn.CellTemplate&gt; &lt;DataTemplate&gt; &lt;StackPanel Orientation="Horizontal"&gt; &lt;Button Content="Edit" Click="EditButtonClick"/&gt; &lt;Button Content="Delete" Command="{Binding DataContext.RemoveLecturer, ElementName=LecturersDataGrid}" /&gt; &lt;/StackPanel&gt; &lt;/DataTemplate&gt; &lt;/DataGridTemplateColumn.CellTemplate&gt; &lt;/DataGridTemplateColumn&gt; &lt;/DataGrid.Columns&gt; &lt;/DataGrid&gt; </code></pre> <p><code>Lecturers</code> are fetched from database in <code>LecturerListViewModel</code> constructor in this way: </p> <pre class="lang-cs prettyprint-override"><code>/// /// Code within LecturerListViewModel class: /// // All lecturers from database. public ObservableCollection&lt;Lecturer&gt; Lecturers // Constructor public LecturerListViewModel() { // Call to Data Access Layer: Lecturers = new ObservableCollection&lt;Lecturer&gt;(_dataAccess.GetAllLecturers()); // Some other stuff here... } private Lecturer _selectedLecturer; // Currently selected row with lecturer. public Lecturer SelectedLecturer { get { return _selectedLecturer; } set { SetProperty(out _selectedLecturer, value, x =&gt; x.SelectedLecturer); } } /// /// Data Access Layer (within DataAccess class): /// public IEnumerable&lt;Lecturer&gt; GetAllLecturers() { using (var dbb = new AcademicTimetableDbContext()) { var query = from b in dbb.Lecturers.Include(l =&gt; l.AcademicDegree).Include(l =&gt; l.Timetables).Include(l =&gt; l.Courses) select b; return query.ToList(); } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload