更新使用实体框架(延迟加载和虚拟财产)数据库记录(Updating database record

2019-08-02 17:12发布

我在数据库中更新现有讲师的数据挣扎。
每个讲师具有由他教 ,AcademicDegree课程 /她( 课程==教训 )。

事实上,有更多的性能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.Namelecturer.AcademicDegreelecturer.Courses )。

这是非常方便的方法,因为在视图模型我可以调用_dataAccess.UpdateLecturer(SelectedLecturer)其中SelectedLecturer在绑定XAML ; SelectedLecturer属性可以通过用户在设置TextBox ES和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_LecturerNameAcademic_Degree_IdAcademicDegree 除外Courses这之后是不变db.SaveChanges()

为什么? 我怎样才能解决这个问题?


类似的问题:

  • 更新-AN-实体在实体框架
  • 怎么办,可以-I连接-A-实体框架对象-也就是说,未启用,来自该数据库
  • 使用-的DbContext式-EF-特征CTP5部分-4-附加附接和-实体- states.aspx
  • 实体框架更新管理与相关实体
  • 实体框架代码先无装卸方法-上的DbContext

-编辑-

我也试过这样(的想法来自这个职位 ):

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 。 在查看DataGrid与DATABSE获取所有讲师名单。 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();
    }
}

Answer 1:

状态设置为ModifiedSetValues仅更新的标量属性Lecturer实体。 更新Courses集合(这是不是标属性)需要更多的工作。 您必须处理一个疗程可能是从集合中删除的情况下,当然可能已添加或课程的标量性质可能已被修改。

另外要更新集合的方式取决于当然是取决于讲师与否。 请问过程中需要时,它已经从集合中删除或只做讲师和课程之间的关系需要删除从数据库中删除? 是否新的课程需要被创建时就已经被添加到集合或确实需要建立一个只关系?

如果没有课程必须被删除,没有新课程创建的更新方法看起来是这样的:

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);
            }


文章来源: Updating database record using Entity Framework (lazy loading and virtual properties)