简体   繁体   中英

Two many-to-many relationships for one table

I have some issue with relationships between 3 tables. There are many-to-many relationships between all of them - my model classes are shown below:

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

According to: 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 . I handled with Bus<->Driver connection by creating ViewModels and updating BusController. I'm able to create and edit Bus using a checkbox (list of drivers) properly. However, I have a problem to do the same with Bus<->Lines.

ViewModel folder consists of 3 classes (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 (included changes line creating and editing):

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

Unfortunately, adding any lines to the bus failed. How to handle with this 2 many-to-many relationship for Bus table? I'd appreciate your hints ;) KB

Have you read about Fluent 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");
        });
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM