我正在努力更新数据库中现有的讲师数据。
每位讲师都有姓名, AcademicDegree 和课程,由他/她教授( Courses == Lessons )。
事实上,class Lecturer
中有更多属性,但它们并不相关。为简单起见,我们假设POCO类是以这种方式定义的:
// POCO class (Entity Framework Reverse Engineering Code First)
public class Lecturer
{
public Lecturer()
{
this.Courses = new List<Course>();
}
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<Course> Courses { get; set; }
}
在数据访问层中我有方法void UpdateLecturer(Lecturer lecturer)
,它应该更新Id_Lecturer
等于lecturer.Id_Lecturer
的讲师(使用lecturer.Name
,{{ 1}}和lecturer.AcademicDegree
)。
这是非常方便的方法,因为在 ViewModel 中我可以调用lecturer.Courses
(其中_dataAccess.UpdateLecturer(SelectedLecturer)
绑定在XAML; SelectedLecturer
属性可以设置用户在SelectedLecturer
es和TextBox
)。
不幸的是这个方法:
Checkbox
更新所有内容(即 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();
}
}
,Id_Lecturer
,Name
和Academic_Degree_Id
), AcademicDegree
除Courses
之后db.SaveChanges()
1}}。
为什么呢?我该如何解决?
类似的问题:
- 编辑 -
我也尝试过这种方式(想法来自this post):
public void UpdateLecturer(Lecturer lecturer)
{
using (var db = new AcademicTimetableDbContext())
{
if (lecturer == null)
return;
DbEntityEntry<Lecturer> entry = db.Entry(lecturer);
if (entry.State == EntityState.Detached)
{
Lecturer attachedEntity = db.Set<Lecturer>().Find(lecturer.Id_Lecturer);
if (attachedEntity == null)
entry.State = EntityState.Modified;
else
db.Entry(attachedEntity).CurrentValues.SetValues(lecturer);
}
db.SaveChanges();
}
}
但仍然课程不会覆盖旧值。
- 编辑2 -
在回答@Slauma问题时,我将描述我如何加载SelectedLecturer
(作为参数传递给UpdateLecturer(Lecturer lecturer)
方法)。
我正在实施MVVM概念,因此我在解决方案中设置了查看项目,DataContext
设置为LecturerListViewModel
。在 View 中,DataGrid
列出了从数据库中提取的所有讲师。 DataGrid
以这种方式绑定:
<DataGrid AutoGenerateColumns="False" Name="LecturersDataGrid" HeadersVisibility="Column" IsReadOnly="True" ItemsSource="{Binding Lecturers,Mode=TwoWay}" SelectedItem="{Binding SelectedLecturer, Mode=TwoWay}">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
<DataGridTextColumn Header="Academic degree" Binding="{Binding AcademicDegree.Degree_Name}" />
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Content="Edit" Click="EditButtonClick"/>
<Button Content="Delete" Command="{Binding DataContext.RemoveLecturer, ElementName=LecturersDataGrid}" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
以这种方式从Lecturers
构造函数中的数据库中提取 LecturerListViewModel
:
///
/// Code within LecturerListViewModel class:
///
// All lecturers from database.
public ObservableCollection<Lecturer> Lecturers
// Constructor
public LecturerListViewModel()
{
// Call to Data Access Layer:
Lecturers = new ObservableCollection<Lecturer>(_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 => x.SelectedLecturer); }
}
///
/// Data Access Layer (within DataAccess class):
///
public IEnumerable<Lecturer> GetAllLecturers()
{
using (var dbb = new AcademicTimetableDbContext())
{
var query = from b
in dbb.Lecturers.Include(l => l.AcademicDegree).Include(l => l.Timetables).Include(l => l.Courses)
select b;
return query.ToList();
}
}
答案 0 :(得分:2)
将状态设置为Modified
和SetValues
仅更新Lecturer
实体的标量属性。更新Courses
集合(不是标量属性)需要更多工作。您必须处理可以从集合中删除课程的案例,可以添加课程或者可以修改课程的标量属性。
此外,更新集合的方式取决于课程是否依赖于讲师。从集合中删除课程时是否需要从数据库中删除课程,还是只需要删除讲师与课程之间的关系?添加到集合中时是否需要创建新课程或者只需要建立关系?
如果没有必须删除课程且没有创建新课程,则Update方法可能如下所示:
public void UpdateLecturer(Lecturer lecturer)
{
using(var db = new AcademicTimetableDbContext())
{
if (lecturer == null)
return;
var lecturerInDb = db.Lecturers
.Include(l => l.Courses)
.Single(l => l.Id_Lecturer == lecturer.Id_Lecturer);
// Update lecturer
db.Entry(lecturerInDb).CurrentValues.SetValues(lecturer);
// Remove courses relationships
foreach (var courseInDb in lecturerInDb.Courses.ToList())
if (!lecturer.Courses.Any(c => c.Id_Course == courseInDb.Id_Course))
lecturerInDb.Courses.Remove(courseInDb);
foreach (var course in lecturer.Courses)
{
var courseInDb = lecturerInDb.Courses.SingleOrDefault(
c => c.Id_Course == course.Id_Course);
if (courseInDb != null)
// Update courses
db.Entry(courseInDb).CurrentValues.SetValues(course);
else
{
// Add courses relationships
db.Courses.Attach(course);
lecturerInDb.Courses.Add(course);
}
}
}
db.SaveChanges();
}
根据您的方案的详细信息,正确的解决方案可能略有不同。
修改强>
如果lecturer.Courses
集合中的课程引用了lecturer
(可能有Lecturer
导航属性),那么当您将此课程中的课程附加到该课程时,您可能会遇到问题上下文因为lecturerInDb
已经附加并具有相同的密钥。您可以尝试更改最后一个else
块,以便有希望解决问题:
else
{
// Add courses relationships
var courseToAttach = new Course { Id_Course = course.Id_Course };
db.Courses.Attach(courseToAttach);
lecturerInDb.Courses.Add(courseToAttach);
}