实体框架多对多关系值未保存在数据库中

时间:2014-01-02 01:27:27

标签: vb.net asp.net-mvc-4 entity-framework-5

我使用Code First和Entity Framework 5建立了多对多关系。已经创建了连接表,但是字段数据没有保存到数据库中。

正在成功地将worker添加到Project对象中并且db.SaveChanges()方法执行时没有错误,但是当再次调用/ Project / Edit / x操作的GET请求时,Workers列表属性为空。

如何通过POST“保存”后,如何在GET请求中持久保存和检索连接的Worker数据?

控制器:ProjectController.vb

POST:/ Project / Create / x

    For i As Integer = LBound(strWorkerIds) To UBound(strWorkerIds)
        Dim workerId As Integer
        If Integer.TryParse(Trim(strWorkerIds(i)), workerId) Then
            Dim worker As Worker = db.Workers.Find(workerId)
            If Not worker Is Nothing Then
                project.Workers.Add(worker)
            End If
        End If
    Next

    If ModelState.IsValid Then
        db.Projects.Add(project)
        db.SaveChanges() ' The project is saved along with the correct project.Workers list
        Return RedirectToAction("Index", "Home")
    End If

POST:/ Project / Edit / x

    For i As Integer = LBound(strWorkerIds) To UBound(strWorkerIds)
        Dim workerId As Integer
        If Integer.TryParse(Trim(strWorkerIds(i)), workerId) Then
            Dim worker As Worker = db.Workers.Find(workerId)
            If Not worker Is Nothing Then
                project.Workers.Add(worker)
            End If
        End If
    Next

    If ModelState.IsValid Then
        db.Entry(project).State = EntityState.Modified
        db.SaveChanges() 'The changes to project.Workers list are NOT being saved?
        Return RedirectToAction("Index", "Home")
    End If

型号:Project.vb

Public Class Project

    Public Sub New()
        Me.Workers = New List(Of Worker)()
    End Sub

    Public Property ProjectID As Integer
    'other properties...
    Public Overridable Property Workers As ICollection(Of Worker)

End Class

型号:Worker.vb

Public Class Worker

    Public Sub New()
        Me.Projects = New List(Of Project)()
    End Sub

    Public Property WorkerID As Integer
    'other properties...
    Public Overridable Property Projects As ICollection(Of Project)

End Class

数据库上下文:ProjectLogContext.vb

Imports System.Data.Entity
Imports System.Data.Entity.ModelConfiguration.Conventions

Public Class ProjectLogContext

    Inherits DbContext

    Public Property Projects As DbSet(Of Project)
    Public Property Workers As DbSet(Of Worker)

    Protected Overrides Sub OnModelCreating(modelBuilder As DbModelBuilder)
        MyBase.OnModelCreating(modelBuilder)

        modelBuilder.Conventions.Remove(Of PluralizingTableNameConvention)()

        modelBuilder.Entity(Of Worker)().HasMany(Function(w) w.Projects) _
            .WithMany(Function(p) p.Workers) _
            .Map(Function(x) x.MapLeftKey("WorkerID").MapRightKey("ProjectID") _
                 .ToTable("WorkerProject"))

    End Sub

End Class

2 个答案:

答案 0 :(得分:2)

将父状态的状态设置为Modified不会对多对多关联中的关系产生任何影响。要实现正确的更新,您必须从数据库加载当前实体图(父项包括其子项),然后如果其ID在您的ID列表中或删除添加子项>如果孩子的ID在ID列表中,则该孩子。 EF的更改跟踪将遵循加载图的这些修改,并生成必要的INSERT和DELETE语句以更新链接表。它在Edit POST操作中可能看起来像这样(在C#中):

var projectInDb = db.Projects.Include(p => p.Workers)
    .SingleOrDefault(p => p.ProjectID == project.ProjectID);

if (projectInDb != null)
{
    // Convert string list to integer list
    var workerIds = new List<int>();
    foreach (string strWorkerId in strWorkerIds)
    {
        int workerId;
        if (int.TryParse(strWorkerId.Trim(), out workerId))
            workerIds.Add(workerId);
    }

    // Update scalar properties of the project
    db.Entry(projectInDb).CurrentValues.SetValues(project);

    // Remove workers
    foreach (var workerInDb in projectInDb.Workers.ToList())
    {
        if (!workerIds.Contains(workerInDb.WorkerID))
            projectInDb.Workers.Remove(workerInDb);
    }

    // Add workers
    foreach (int workerId in workerIds)
    {
        if (!projectInDb.Workers.Any(w => w.WorkerID == workerId))
        {
            var workerInDb = db.Workers.Find(workerId);
            if (workerInDb != null)
                projectInDb.Workers.Add(workerInDb);
        }
    }

    db.SaveChanges();
}

答案 1 :(得分:0)

我希望您在GET中获取项目时附加到项目的'包括'工作者:/ Project / Edit / x操作。我在C#中复制了您的问题,如果我在GET:/ Project / Edit / x操作中的lambda表达式中包含worker,我可以获得附加到项目的Workers列表。这是ProjectController代码fyr。

readonly ProjectLogContext _db = new ProjectLogContext();
// GET: /Project/
    public ActionResult Index()
    {
        var model = _db.Projects.ToList();
        return View(model);
    }

    //GET: /Project/Create/x
    public ActionResult Create()
    {
        return View();
    }

    //POST: /Project/Create/x
    [HttpPost]
    public ActionResult Create(Project project)
    {
        string[] strWorkerIds = { "26", "27", "28" };

        for (var i = strWorkerIds.GetLowerBound(0); i <= strWorkerIds.GetUpperBound(0); i++)
        {
            int workerId;
            if (!int.TryParse(strWorkerIds[i], out workerId)) continue;
            var worker = _db.Workers.Find(workerId);
            if (worker != null)
            {
                project.Workers.Add(worker);
            }
        }

        if (!ModelState.IsValid) return View();
        _db.Projects.Add(project);
        _db.SaveChanges();
        return RedirectToAction("Index", "Project");
    }


    //GET: /Project/Create/x
    public ActionResult Edit(int id)
    {
        var query = _db.Projects.Include(p => p.Workers).Single(p => p.ProjectId == id);
        return View(query);
    }

    //POST: /Project/Create/x
    [HttpPost]
    public ActionResult Edit(Project project)
    {
        if (!ModelState.IsValid) return View();
        _db.Entry(project).State = EntityState.Modified;
        _db.SaveChanges();
        return RedirectToAction("Index", "Project");
    }