一张表有两个多对多关系

3

我在三张表格之间的关系上遇到了问题。它们之间都存在多对多的关系 - 我的模型类如下所示:

public partial class Bus
{
    public Bus()
    {
        this.Lines = new HashSet<Line>();
        this.Drivers = new HashSet<Driver>();
    }

    public int BusID { get; set; }
    public string RegNum { get; set; }
    [StringLength(3)]
    public string Status { get; set; }

    public virtual ICollection<Line> Lines { get; set; }
    public virtual ICollection<Driver> Drivers { get; set; }
}

    public partial class Driver
{
    public Driver()
    {
        this.Buses = new HashSet<Bus>();
    }

    public int DriverID { get; set; }
    public string DriverName { get; set; }
    public string DriverSurname { get; set; }
    [StringLength(3)]
    public string Status { get; set; }

    [Display(Name = "Driver")]
    public string DriverInfo
    {
        get
        {
            return DriverName + " " + DriverSurname;
        }
    }

    public virtual ICollection<Bus> Buses { get; set; }
}


public partial class Line
{
    public Line()
    {
        this.Schedules = new HashSet<Schedule>();
        this.Buses = new HashSet<Bus>();
    }

    public int LineID { get; set; }
    public int LineNumber { get; set; }
    public string Direction { get; set; }

    [Display(Name = "Line: Direction")]
    public string LineInfo
    {
        get
        {
            return LineNumber + ": " + Direction;
        }
    }

    public virtual ICollection<Bus> Buses { get; set; }
}

DbContext:

public partial class ModelEntities : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        throw new UnintentionalCodeFirstException();
    }

    public virtual DbSet<Bus> Buses { get; set; }
    public virtual DbSet<Driver> Drivers { get; set; }
    public virtual DbSet<Line> Lines { get; set; }
}

根据https://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-a-more-complex-data-model-for-an-asp-net-mvc-application,我通过创建ViewModels并更新BusController来处理Bus<->Driver连接。我能够使用复选框(司机列表)正确地创建和编辑Bus。 但是,我在Bus<->Lines上遇到了问题。
ViewModel文件夹包含3个类(AssignedDriverData、BusIndexData、AssignedLineData)。
public class AssignedDriverData
{
    public int DriverID { get; set; }
    public string DriverName { get; set; }
    public string DriverSurname { get; set; }

    public string DriverInfo
    {
        get
        {
            return DriverName + " " + DriverSurname;
        }
    }
    public bool Assigned { get; set; }
}

public class BusIndexData
{
    public IEnumerable<Bus> Buses { get; set; }
    public IEnumerable<Driver> Drivers { get; set; }
    public IEnumerable<Line> Lines { get; set; }
}

public class AssignedLineData
{
    public int LineID { get; set; }
    public int LineNumber { get; set; }
    public string Direction { get; set; }

    public string LineInfo
    {
        get
        {
            return LineNumber + ": " + Direction;
        }
    }
    public bool Assigned { get; set; }
}

BusController(包括更改线路创建和编辑):

public class BusesController : Controller
{
    private ModelEntities db = new ModelEntities();

    // GET: Buses
    public ActionResult Index()
    {
        return View(db.Buses.ToList());
    }

    // GET: Buses/Details/5
    public ActionResult Details(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        Bus bus = db.Buses.Find(id);
        if (bus == null)
        {
            return HttpNotFound();
        }
        return View(bus);
    }

    // GET: Buses/Create
    public ActionResult Create()
    {
        //***************** adding drivers  ******************//
        var bus = new Bus();
        bus.Drivers = new List<Driver>();
        PopulateAssignedDriverData(bus);

        bus.Lines = new List<Line>();   //********* adding lines*********************//
        PopulateAssignedLineData(bus); //********* adding lines*********************//
        //************************************************//
        return View();
    }

    // POST: Buses/Create
    // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
    // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "BusID,RegNum,Status")] Bus bus, string[] selectedDrivers, string[] selectedLines)
    {

        //******************* adding drivers **********************//
        if (selectedDrivers != null)
        {
            bus.Drivers = new List<Driver>();
            foreach (var course in selectedDrivers)
            {
                var driverToAdd = db.Drivers.Find(int.Parse(course));
                bus.Drivers.Add(driverToAdd);
            }
        }
        //************************************************//


        //******************* adding lines **********************//
        if (selectedLines != null)
        {
            bus.Lines = new List<Line>();
            foreach (var line in selectedLines)
            {
                var lineToAdd = db.Lines.Find(int.Parse(line));
                bus.Lines.Add(lineToAdd);
            }
        }
        //************************************************//


        if (ModelState.IsValid)
        {
            db.Buses.Add(bus);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        //************************************************//
        PopulateAssignedDriverData(bus);
        PopulateAssignedLineData(bus);
        //************************************************//
        return View(bus);
    }

    // GET: Buses/Edit/5
    public ActionResult Edit(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }

        //************** editing drivers ********************//
        Bus bus = db.Buses
            .Include(i => i.Drivers)
            .Include(i => i.Lines) //****** for editing lines ******//
            .Where(i => i.BusID == id)
            .Single();
        PopulateAssignedDriverData(bus);
        //************************************************//


        if (bus == null)
        {
            return HttpNotFound();
        }
        return View(bus);
    }

    // POST: Buses/Edit/5
    // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
    // more details see http://go.microsoft.com/fwlink/?LinkId=317598.


    //************** editing with drivers and lines ********************//

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(int? id, string[] selectedDrivers, string[] selectedLines)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        var busToUpdate = db.Buses
           .Include(i => i.Drivers)
           .Include(i => i.Lines) //****** added for lines *******//
           .Where(i => i.BusID == id)
           .Single();

        if (TryUpdateModel(busToUpdate, "",
           new string[] { "BusID,RegNum,Status" }))
        {
            try
            {
                UpdateBusDrivers(selectedDrivers, busToUpdate);
                UpdateBusDrivers(selectedLines, busToUpdate); //****** added for lines *******//
                db.SaveChanges();

                return RedirectToAction("Index");
            }
            catch (RetryLimitExceededException /* dex */)
            {
                //Log the error (uncomment dex variable name and add a line here to write a log.
                ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
            }
        }
        PopulateAssignedDriverData(busToUpdate);
        PopulateAssignedLineData(busToUpdate); //****** added for lines *******//
        return View(busToUpdate);
    }
    //************************************************//


    // GET: Buses/Delete/5
    public ActionResult Delete(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        Bus bus = db.Buses.Find(id);
        if (bus == null)
        {
            return HttpNotFound();
        }
        return View(bus);
    }

    // POST: Buses/Delete/5
    [HttpPost, ActionName("Delete")]
    [ValidateAntiForgeryToken]
    public ActionResult DeleteConfirmed(int id)
    {
        Bus bus = db.Buses.Find(id);
        db.Buses.Remove(bus);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            db.Dispose();
        }
        base.Dispose(disposing);
    }


    //********************** adding drivers ******************//
    private void PopulateAssignedDriverData(Bus bus)
    {
        var allDrivers = db.Drivers;
        var busDrivers = new HashSet<int>(bus.Drivers.Select(c => c.DriverID));
        var viewModel = new List<AssignedDriverData>();
        foreach (var driver in allDrivers)
        {
            viewModel.Add(new AssignedDriverData
            {
                DriverID = driver.DriverID,
                DriverName = driver.DriverName,
                DriverSurname = driver.DriverSurname,
                Assigned = busDrivers.Contains(driver.DriverID)
            });
        }
        ViewBag.Drivers = viewModel;
    }
    //************************************************//



    //**************** editing drivers ***********************//
    private void UpdateBusDrivers(string[] selectedDrivers, Bus busToUpdate)
    {
        if (selectedDrivers == null)
        {
            busToUpdate.Drivers = new List<Driver>();
            return;
        }

        var selectedDriversHS = new HashSet<string>(selectedDrivers);
        var busDrivers = new HashSet<int>
            (busToUpdate.Drivers.Select(c => c.DriverID));
        foreach (var driver in db.Drivers)
        {
            if (selectedDriversHS.Contains(driver.DriverID.ToString()))
            {
                if (!busDrivers.Contains(driver.DriverID))
                {
                    busToUpdate.Drivers.Add(driver);
                }
            }
            else
            {
                if (busDrivers.Contains(driver.DriverID))
                {
                    busToUpdate.Drivers.Remove(driver);
                }
            }
        }
    }
    //************************************************//



    //********************** adding lines ******************//
    private void PopulateAssignedLineData(Bus bus)
    {
        var allLines = db.Lines;
        var busLines = new HashSet<int>(bus.Lines.Select(c => c.LineID));
        var viewModel = new List<AssignedLineData>();
        foreach (var line in allLines)
        {
            viewModel.Add(new AssignedLineData
            {
                LineID = line.LineID,
                Direction = line.Direction,
                LineNumber = line.LineNumber,
                Assigned = busLines.Contains(line.LineID)
            });
        }
        ViewBag.Lines = viewModel;
    }
    //************************************************//

    //**************** editing lines ***********************//
    private void UpdateBusLines(string[] selectedLines, Bus busToUpdate)
    {
        if (selectedLines == null)
        {
            busToUpdate.Lines = new List<Line>();
            return;
        }

        var selectedLinesHS = new HashSet<string>(selectedLines);
        var busLines = new HashSet<int>
            (busToUpdate.Lines.Select(c => c.LineID));
        foreach (var line in db.Lines)
        {
            if (selectedLinesHS.Contains(line.LineID.ToString()))
            {
                if (!busLines.Contains(line.LineID))
                {
                    busToUpdate.Lines.Add(line);
                }
            }
            else
            {
                if (busLines.Contains(line.LineID))
                {
                    busToUpdate.Lines.Remove(line);
                }
            }
        }
    }
    //************************************************//
 }

很遗憾,向公交车添加任何线路都失败了。 如何处理Bus表中的这两个多对多关系? 感谢您的提示;) KB


5
你发布的代码太多与问题无关。如何创建一个最小、完整且可验证的示例 - user3559349
失败了?怎么回事?你收到了错误吗?是什么错误? - Shyju
@Shyju,在DbContext中添加Fluent API后已经解决了;) 没有它,Buses<->Lines之间的关系无法被检测到,现在它可以正常工作了。 - korn
1个回答

1
你读过关于流畅API的文章吗?
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Bus>().HasMany(b => b.Drivers).WithMany(d => d.Buses).Map(m =>
            {
                m.MapLeftKey("BusId");
                m.MapRightKey("DriverID");
                m.ToTable("BusDriverJoinTable");
            });
        modelBuilder.Entity<Bus>().HasMany(b => b.Lines).WithMany(l=>l.Buses).Map(m =>
        {
            m.MapLeftKey("BusId");
            m.MapRightKey("LineID");
            m.ToTable("BusLineJoinTable");
        });
    }

谢谢你,在我的上下文中添加了你的代码后,现在所有的代码都可以正常工作了,包括我在BusController中实现的代码。非常感谢你! :) - korn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接