2

I am having a problem with creating an appropriate ViewModel to allow me to allow user to choose multiple tickets at once in a View.

I have a Ticket model

 public class Ticket
{
   public int TicketID { get; set; }

   [Required]
   [ForeignKey("Event")]
   //foreign key
    public int EventID { get; set; }

   [Required]
   public string Description { get; set; }

   [Required]
   public float Price { get; set; }

    //navigation property
    public virtual Event Event { get; set; }

}

An Order Model

 public class Order
{

    public int OrderID { get; set; }

    //foreign key
    [Required]
    [ForeignKey("Event")]
    public int EventID { get; set; }


    [Required]
    public DateTime OrderDate { get; set; }

    [Required]
    public float OrderTotal { get; set; }

    public ApplicationUser user { get; set; }

    public virtual Event Event { get; set; }
}

Then I have an OrderDetails model

public class OrderDetails
{

    [Required]
    public int OrderDetailsID { get; set; }


    [Required]
    //Foreign key
    [ForeignKey("Order")]
    public int OrderID { get; set; }

    [Required]
    //Foreign key
    [ForeignKey("Ticket")]
    public int TicketID { get; set; }

    [Required]
    public string FirstName { get; set; }

    [Required]
    public string LastName { get; set; }

    [Required]
    [DataType(DataType.EmailAddress)]
    public string email { get; set; }

    [Required]
    [DataType(DataType.PhoneNumber)]
    public int PhoneNumber { get; set; }

    //navigation properties
    public virtual Order Order { get; set; }

    public virtual Ticket Ticket { get; set; }

}

I also created an additional TicketsOrdered model as I don't know where else I can save the quantity of each ticket type a user has selected

public class TicketsOrdered
{

    public int OrderID;

    public int TicketID;

    public int Quantity;
}

I want to create a View which will display the Ticket Description and Price for each Ticket relating to a specific Event then there will also be a dropdown/textbox to allow users to input the quantity of each ticket they require. Then I want to save the TicketID, OrderID and quantity to my TicketsOrdered db table. The problem I am having is that all the data is relating to so many models and I don't know how to bring it all together. I'm at a total loss on how to achieve this, an example of how I want it to look is when you click book tickets on EventBrite. Any help on a ViewModel which will work or how to use my current models in a View would be really helpful thank you.

EDIT Event Model

 public class Event
{
    public int EventID { get; set; }

    [Required]
    public String Name { get; set; }

    [Required]
    public String Location { get; set; }

    [Required]
    [DataType(DataType.Date)]
    public DateTime Date { get; set; }

    [Required]
    [DataType(DataType.MultilineText)]
    public String Description { get; set; }

    [Required]
    [Display(Name = "Total Tickets Available")]
    public int TicketsAvailable { get; set; }

    //navigation property
    public virtual IEnumerable<Order> Order { get; set; }
    //navigation property
    public virtual IEnumerable<Ticket> Tickets { get; set; }

}
6
  • You state for each Ticket relating to a specific Event, but your models suggest you only have one Ticket per event, not a collection of Tickets. What is your Event model? Does it contain a property IEnumerable<Order>? Commented Jan 10, 2016 at 23:05
  • Yes I have an Event model contain IEnumerable <Order> @StephenMuecke. Which model do I need to change to show each event can have multiple tickets? Thanks Commented Jan 10, 2016 at 23:34
  • Its still a little unclear what your relationships are. Does each Event have also have a collection of different Ticket types? And is the idea that you want to create an Order for an Event which displays all the available ticket types for that Event and allow the user to enter a quantity for each (say they want 2 standard tickets and 2 deluxe tickets)? Commented Jan 10, 2016 at 23:52
  • Yes that's exactly what I want to be able to do @StephenMuecke Commented Jan 11, 2016 at 0:01
  • OK - no time now, but I will add an answer in an hour or so showing how the view model and view should be. Note also its unclear why you have separate models for Order and OrderDetails since there seems to be a 1:1 relationship between them Commented Jan 11, 2016 at 0:04

1 Answer 1

2

Start by creating view models that represent what you want to display/edit in the view

public class TicketVM
{
  public int TicketID { get; set; }
  public string Description { get; set; }
  public decimal Price { get; set; }
  public int Quantity { get; set; }
}
public class OrderVM
{
  public int ID { get; set; }
  public int EventID { get; set; }
  public string EventName { get; set; }
  // additional properties of Event you want to display
  public DateTime OrderDate { get; set; }
  public string FirstName { get; set; }
  // additional properties of Order and OrderDetails you want to edit
  public List<TicketVM> Tickets { get; set; }
}

Side note: Its a bit unclear why you have separate models for Order and OrderDetails, or why OrderDetails has public int TicketID { get; set; } which suggests an Order can only have one ticket so I suggest you may need some changes to your database structure. If the intention is that a user can order multiple tickets for different people, then the name, email and phone of each ticket holder should probably be stored in the TicketsOrdered table (and those properties added to the TicketVM class)

The view would then be (assuming its for a Create method)

@model TicketVM
@using (Html.BeginForm())
{
  @Html.HiddenFor(m => m.EventID)
  <h2>@Model.EventName</h2>
  // other display properties of event
  @Html.TextBoxFor(m => m.OrderDate)
  @Html.TextBoxFor(m => m.FirstName)
  // other edit control for properties of Order and OrderDetails (see note above)
  @Html.EditorFor(m => m.Tickets)
  <input type="submit" value="Save" />
}

and the EditorTemplate for TicketVM (in /Views/Shared/EditorTemplates/TicketVM.cshtml)

@model TicketVM
@Html.HiddenFor(m => m.TicketID)
@Html.DisplayFor(m => m.Description)
@Html.DisplayFor(m => m.Price)
@Html.TextBoxFor(m => m.Quantity)

Then the controller methods would be (note you have not shown you Event model so adjust the following to suit)

public ActionResult Create(int ID) // assumes ID is the ID of the Event
{
  // Get the event and its tickets
  Event e = db.Events.Where(e = e.EventID = ID).Include(e => e.Tickets);
  // Initialize a new order
  OrderVM model = new OrderVM
  {
    EventID = e.EventID,
    EventName = e.EventName,
    // other properties of event as required
    Tickets = e.Tickets.Select(t => new TicketVM
    {
      TicketID = t.TicketID,
      Description = t.Description,
      Price = t.Price
    })
  };
  return View(model);
}
[HttpPost]
public ActionResult Create(OrderVM model)
{
  if (!ModelState.IsValid)
  {
    // repopulate any properties as required
    return View(model);
  }
  // Initialize an Order data model, save it and gets its ID
  Order order = new Order
  {
    OrderDate = model.OrderDate,
    // other properties of Order
  };
  db.Orders.Add(order);
  db.SaveChanges();
  // ditto for OrderDetails (but see notes above)

  // Initialize an TicketsOrdered data model for each valid ticket
  foreach(TicketVM ticket in model.Tickets.Where(t => t.Quantity > 0))
  {
    TicketsOrdered ticketOrder = new TicketsOrdered
    {
      OrderID = order.ID,
      TicketID = ticketOrder.TicketID,
      Quantity = ticketOrder.Quantity
    }
    db.TicketsOrdered.Add(ticketOrder);
  }
  db.SaveChanges();
  return RedirectToAction(...);
}
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you @StephenMuecke. I made an error when I said I had IEnnumerable<Ticket> within my Event model. Then now when I added this to the model I don't know how to add a Ticket to it. I have updated my post to include the Event model. I tried changing IEnnumerable to IList instead so I can use an Add method but this threw an exception concerning this line Tickets = e.Tickets.Select(t => new TicketVm {
Cant see any update with the Event model. But if it does not include a collection property for tickets, then you can populate the OrderVM using something like Tickets = db.Tickets.Where(t => t.EventID = ID).Select(t => new TicketVM { TicketID = t.TicketID, Description = t.Description, Price = t.Price }). But as I mentioned earlier, I suspect there may be a few problems with the design of you database
That's great, thank you so much for all your help, I really appreciate you taking your time to help me out @StephenMuecke!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.