I have a post method in my controller that looks like this and I want AvailableSeats to reduce by 1 anytime I post the form. The problem is when I run the program for the very first time and post the form, everything works perfectly but for subsequent times, the database values for the AvailableSeats doesn't reduce by 1, it just remains constant and I can't figure out why.
[HttpPost]
public ActionResult Create(BookingViewModel viewModel)
{
if (viewModel.FromLocationId == viewModel.ToLocationId)
{
return RedirectToAction("Index");
}
var busFromDb = _context.Buses.First(c=>c.Id == viewModel.BusId);
var seatsFromDb = busFromDb.BusSeats;
var reduce = seatsFromDb - 1;
if (busFromDb != null)
{
var book = new Booking
{
AvailableSeats = reduce,
FromLocationId = viewModel.FromLocationId,
ToLocationId = viewModel.ToLocationId,
BusId = viewModel.BusId,
DateTime = viewModel.DateTime,
};
_context.Bookings.Add(book);
}
_context.SaveChanges();
return RedirectToAction("Index", "Home");
}
My Booking Class
public class Booking
{
[Required]
public int Id { get; set; }
public FromLocation FromLocation { get; set; }
public int FromLocationId { get; set; }
public ToLocation ToLocation { get; set; }
public int ToLocationId { get; set; }
public Bus Bus { get; set; }
[Required]
public int BusId { get; set; }
public DateTime DateTime { get; set; }
public int AvailableSeats { get; set; }
}
My Bus class
public class Bus
{
public int Id { get; set; }
public string BusNumber { get; set; }
public BusService BusService { get; set; }
public int BusSeats { get; set; }
}
As requested, this is my DbContext class
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public DbSet<Bus> Buses { get; set; }
public DbSet<Booking> Bookings { get; set; }
public DbSet<FromLocation> FromLocations { get; set; }
public DbSet<ToLocation> ToLocations { get; set; }
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
After which I initialized it in my controller.
public class BookingsController : Controller
{
private ApplicationDbContext _context;
public BookingsController()
{
_context = new ApplicationDbContext();
}
Currently, you are deducting total bus seats by 1 (24 - 1) that always return 23 for each booking because you don't update the value 24 from Bus table, I am assuming which is total number of seats in a given bus. Rather you can count total bookings made for per bus that gives you the remaining seats.
int seatsFromDb = busFromDb.BusSeats; //24
int soldSeats = _context.Bookings.Count(b => b.BusId == viewModel.BusId); //2 (you need to add more filters)
int remainingSeats = seatsFromDb - (soldSeats + 1) //include the current booking (sold 3)
var book = new Booking
{
AvailableSeats = remainingSeats,
// ...
Hi I tried this code with same entitty structure and now result is that on every booking the bus table BusSeats reduce to one and in Booking table availabe seats reduce to one. I think this is want you wanted.
public ActionResult Index()
{
-- I hardcoded id because I donthave all view model but with this i was able to achieve the result you required.
int BusId = 1;
var _context = new TestContext();
var busFromDb = _context.Buses.FirstOrDefault(c => c.Id == BusId);
var seatsFromDb = busFromDb.BusSeats;
var reduce = seatsFromDb - 1;
if (busFromDb != null)
{
busFromDb.BusSeats = busFromDb.BusSeats - 1;
var book = new Booking
{
AvailableSeats = reduce,
BusId = BusId,
DateTime =DateTime.Now,
Bus = busFromDb
};
book.Bus = busFromDb;
_context.Entry(busFromDb).State = EntityState.Modified;
_context.Bookings.Add(book);
}
_context.SaveChanges();
return View();
}
Below is my EF classes
public class TestContext:DbContext
{
public TestContext()
: base("name=TestConnection")
{
}
public virtual DbSet<Bus> Buses { get; set; }
public virtual DbSet<Booking> Bookings { get; set; }
}
}
public class Booking
{
public int Id { get; set; }
public Bus Bus { get; set; }
public int BusId { get; set; }
public DateTime DateTime { get; set; }
public int AvailableSeats { get; set; }
}
public class Bus
{
public int Id { get; set; }
public string BusNumber { get; set; }
public int BusSeats { get; set; }
}
Related
I am trying to bind a model in a post action method. i.e binding with the help of [Bind] attribute.
Where I post some fields for parent while a collection of child properties at the same time.
Supose I have parent as following
class Parent
{
int field0;
string field1;
string field2;
ICollection<Child> Children;
}
class Child
{
int field3;
string field4;
string field5;
}
at the time of binding I can choose fields to bind for simple binding like [Bind("field1, field2")] and to include children as well then [Bind("field1,field2,children")]
But I need to include some fields of children like children("field4", "field5")
Is there any possibility so that I can write like following
public IActionResult UTOneFlight([Bind("field1, field2, children(field4, field5)")] Parent p)
{
}
UPDATE
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> UTOneFlight([Bind("FlightID, SrcAirportID, DestAirportID, FlightDate, Sector, RegistrationNo, FlightNo, CallSign, CrewMembers, EmbDetails, UpdateRemarks")] FlightViewModel f)
{
if (f != null && f.EmbDetails != null)
{
if (f.FlightID == 0)
{
var flight = new Flight()
{
EmbDetails = new List<EmbDetail>(),
FlightType = "emb",
AirlineOperatorID = _user.OperatorID,
SrcAirportID = f.SrcAirportID,
DestAirportID = f.DestAirportID,
FlightDate = f.FlightDate,
Sector = f.Sector.ToString().ToLower()[0],
FlightNo = f.FlightNo.Trim().ToLower(),
CallSign = f.CallSign.Trim().ToLower(),
RegistrationNo = f.RegistrationNo.Trim().ToLower(),
CrewMembers = f.CrewMembers,
UpdateRemarks = f.UpdateRemarks?? f.UpdateRemarks,
EmbDataStatus = 'u',
CreatedBy = _user.UserID
};
foreach (var e in f.EmbDetails)
{
flight.EmbDetails.Add(
new EmbDetail()
{
PaxType = e.PaxType,
PaxClass = e.PaxClass,
AdultPax = e.AdultPax,
Infants = e.Infants,
Dips = e.Dips,
FOC = e.FOC,
TransferPax = e.TransferPax,
CreatedBy = _user.UserID
}
);
}
await _db.AddAsync(flight);
return RedirectToAction("Index");
}
else
{
//var flight = await _db.SingleAsync<Flight>(x => x.FlightID == f.FlightID);
//return RedirectToAction("Index");
}
}
else
return NotFound();
}
and my models are
public class FlightViewModel
{
public long FlightID { get; set; }
public int SrcAirportID { get; set; }
public int DestAirportID { get; set; }
public string RegistrationNo { get; set; }
public string FlightNo { get; set; }
public string CallSign { get; set; }
public DateTime FlightDate { get; set; }
public int CrewMembers { get; set; }
public char Sector { get; set; }
public string UpdateRemarks { get; set; }
public ICollection<EmbDetViewModel> EmbDetails { get; set; }
}
and
public class EmbDetViewModel
{
public string PaxType { get; set; }
public char PaxClass { get; set; }
public int AdultPax { get; set; }
public int Infants { get; set; }
public int Dips { get; set; }
public int Crew { get; set; }
public int FOC { get; set; }
public int TransferPax { get; set; }
}
I need to write signature of the method like
public async Task<IActionResult> UTOneFlight([Bind("FlightID, SrcAirportID, DestAirportID, FlightDate, Sector, RegistrationNo, FlightNo, CallSign, CrewMembers, EmbDetails(PaxType, PaxClass), UpdateRemarks")] FlightViewModel f)
Please have a look at
EmbDetails(PaxType, PaxClass)
How do you send your request body? I test in my side and here's the result.
My model:
public class ParentTestModel
{
public int id { get; set; }
public ICollection<TestModel> testModels { get; set; }
}
public class TestModel
{
public string prefix { get; set; }
}
==============================Update=============================
I test in my side with [JsonIgnore] and the property which added this annotation will be ignored and this is suitable when the request body is a json object like the screenshot above. And if you are sending the request in form-data then you can use [Bind] annotation, I think you may have referred to this document.
I have successfully inserted data into two tables which are working fine. Now I am just stuck as to how I can get the details from both tables and update them. After inserting, I want to query both tables using an id and get the records, and then use the Id to update.
This is what I am looking for.
get data from two tables
update tables(pass id)
It must be an API that communicates with my classes because I want to display the data from the view
DB Models
1.
public class WholesaleRateSheetMarkup
{
[Key]
public int RateSheetMarkupId { get; set; }
[Required]
public int ResellerId { get; set; }
[StringLength(50)]
public string RatesheetName { get; set; }
}
2.
public class WholesaleRateSheet
{
[Key]
public int RateSheetId { get; set; }
[Required]
public int RateSheetMarkupId { get; set; }
public string CountryCode { get; set; }
public string Description { get; set; }
public decimal Peak { get; set; }
public bool IsSouthAfricanRate { get; set; }
public bool IsInertnationRate { get; set; }
public bool IsSpecificRate { get; set; }
public int DestinationGroupSetId { get; set; }
public int DestinationGroupId { get; set; }
public string DestinationLookup { get; set; }
public DateTime CreatedDate { get; set; }
public string CreatedByUsername { get; set; }
public DateTime LastUpdatedDate { get; set; }
public string UpdatedByUsername { get; set; }
}
My controller: This controller calls service class
[HttpPost]
[Route("[controller]/addRateSheet/{resellerId}/{productName}")]
public IActionResult AddRateSheet(int resellerId, string productName , int destinationGroupSetId, [FromBody]List<RateSheetSummary> rateSheetSummaries)
{
RateSheetService rateSheetService = new RateSheetService();
return Ok(rateSheetService.SaveRateSheet(resellerId, productName, rateSheetSummaries));
}
This is how I am saving to the database
public RateSheetModel SaveRateSheet(int resellerId, string productName, [FromBody]List<RateSheetSummary> rateSheetSummaries)
{
int latestId;
RateSheetModel rateSheetModel = new RateSheetModel();
try
{
#region Save rate sheet to the tabase
if (RateSheetObj != null)
{
#region WholesaleRateSheetMarkup
var wholesaleRateSheetMarkup = new WholesaleRateSheetMarkup
{
ResellerId = resellerId,
RatesheetName = productName,
};
_Context.WholesaleRateSheetMarkup.Add(wholesaleRateSheetMarkup);
_Context.SaveChanges();
//get latest RateSheetMarkupId
latestId = wholesaleRateSheetMarkup.RateSheetMarkupId;
#endregion
#region WholesaleRateSheet
#region commented out
List<WholesaleRateSheet> wholesaleRateSheets = new List<WholesaleRateSheet>();
foreach (var item in rateSheetSummaries)
{
wholesaleRateSheets.Add(new WholesaleRateSheet()
{
RateSheetMarkupId = latestId,
CountryCode = item.CountryCode,
Description = item.Description,
Peak = item.Peak,
IsSouthAfricanRate = item.IsSouthAfricanRate,
IsSpecificRate = item.IsSpecificRate,
DestinationGroupSetId = 1,
DestinationGroupId = 1,
DestinationLookup = item.DestinationLookup,
CreatedDate = DateTime.Now
}); ;
_Context.WholesaleRateSheet.AddRange(wholesaleRateSheets);
_Context.SaveChanges();
}
#endregion
}
}
}
}
Trying to fetch data from my tables. At this point, I don't know how to continue further as I want to get the details and so that I can bind the data from the view.
public RateSheetModel getRatesheetDetails(int rateSheetMarkupId)
{
RateSheetModel model = new RateSheetModel();
using (var context = new AppClientZoneContext())
{
var select = (from rsm in context.WholesaleRateSheetMarkup
join rs in context.WholesaleRateSheet
on rsm.RateSheetMarkupId equals rs.RateSheetMarkupId
where rsm.RateSheetMarkupId == rateSheetMarkupId
select new
{
rsm.RatesheetName,
rs.CountryCode,
rs.Description,
rs.Peak,
rs.IsSouthAfricanRate,
rs.IsInertnationRate,
rs.RateSheetMarkupId,
rs.IsSpecificRate,
rs.DestinationGroupSetId,
rs.DestinationGroupId,
rs.DestinationLookup,
rs.CreatedDate,
rs.CreatedByUsername,
rs.LastUpdatedDate,
rs.UpdatedByUsername,
}).FirstOrDefault();
}
return model;
}
Update API
[HttpPost]
[Route("[controller]/updateRateSheet/{resellerId}/{ratesheetId}")]
public IActionResult UpdateRateSheet(int resellerId, int ratesheetId, string productName)
{
RateSheetService UpdateRateSheetService = new RateSheetService();
return Ok(UpdateRateSheetService.UpdateRateSheet(resellerId,ratesheetId, productName));
}
Update function: I don't know how to best approach update functionality
public RateSheetModel UpdateRateSheet(int resellerId, int rateSheetId, string productName)
{
RateSheetModel mm = new RateSheetModel();
return mm;
}
I have a 3 level entity and I am having some trouble saving it.
public partial class Event
{
public Event()
{
Recurrences = new HashSet<Recurrence>();
}
public int Id { get; set; }
public string Title { get; set; }
public ICollection<Recurrence> Recurrences { get; set; }
}
public partial class Recurrence
{
public Recurrence()
{
AspNetUsers = new HashSet<AspNetUser>();
}
public int Id { get; set; }
public int EventId { get; set; }
public string Venue { get; set; }
public ICollection<AspNetUser> AspNetUsers { get; set; }
}
public partial class AspNetUser
{
public AspNetUser()
{
Recurrences = new HashSet<Recurrence>();
}
public string Id { get; set; }
public string UserName { get; set; }
public ICollection<Recurrence> Recurrences { get; set; }
}
The Post controller for the Event Class looks like this:
// POST: api/Events
[ResponseType(typeof(Event))]
public async Task<IHttpActionResult> PostEvent(EventDTO #event)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var newEvent = new Event();
newEvent.Title = #event.Title;
newEvent.EventTypeId = #event.EventTypeId;
var recurrence = new Recurrence();
recurrence.Venue = #event.Venue;
var users = db.AspNetUsers.Where(u => #event.UserId.Contains(u.Id));
foreach (var u in users)
recurrence.AspNetUsers.Add(u);
newEvent.Recurrences.Add(recurrence);
db.Events.Add(newEvent);
await db.SaveChangesAsync();
return CreatedAtRoute("DefaultApi", new { id = newEvent.Id }, newEvent);
}
When I call the PostEvent method with an Event like DTO i get the http error code 500.
first, how can i add exception handling to capture the specific error and secondly, what I'm I doing wrong here?
Any help is deeply appreciated.
Thanks.
I have been searching for days now trying to figure this one out. It saves my records correctly but throws the following error:
The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state. Inner exception message: Unable to set field/property Actors on entity type BOR.DataModel.StagComplaint. See InnerException for details.
I am using Code First and EF 5 in a C# Web Forms solution with a supporting WCF Service. Here are my POCO classes:
public partial class StagComplaint : ComplaintBase {
public IList<StagParcel> Parcels { get; set; }
public IList<StagActor> Actors { get; set; }
public IList<StagRectification> Rectifications { get; set; }
public ComplaintType ComplaintType { get; set; }
public int ComplaintTypeID { get; set; }
public StagComplaint() {
this.Parcels = new List<StagParcel>();
this.Actors = new List<StagActor>();
this.Rectifications = new List<StagRectification>();
}
}
public class ComplaintBase : BORBase {
public string Number { get; set; }
public int ParentID { get; set; }
public int TaxYear { get; set; }
public string Category { get; set; }
public double BuildingValue { get; set; }
public double LandValue { get; set; }
public double OwnerOpinion { get; set; }
public string Notes { get; set; }
}
public class BORBase {
[Required]
public DateTime CreationDate { get; set; }
public int ID { get; set; }
[MaxLength(25)]
[Required]
public string UserIdentification { get; set; }
}
public partial class StagParcel : ParcelBase {
public virtual StagActor Owner { get; set; }
[ForeignKey("Owner")]
public int OwnerID { get; set; }
public StagAddress Address { get; set; }
[IgnoreDataMember]
public virtual StagComplaint Complaint { get; set; }
public int ComplaintID { get; set; }
public StagParcel() {
this.Address = new StagAddress();
}
}
public class ParcelBase : BORBase {
public string Number { get; set; }
public double BuildingValue { get; set; }
public double LandValue { get; set; }
public double OwnerOpinion { get; set; }
public string LandUseCode { get; set; }
public string NeighborhoodCode { get; set; }
public string TaxDistrict { get; set; }
public string SchoolDistrict { get; set; }
public int SchoolBoardID { get; set; }
}
public partial class StagActor : ActorBase {
public StagAddress Address { get; set; }
public virtual IList<StagEmail> Emails { get; set; }
public virtual IList<StagPhone> Phones { get; set; }
[IgnoreDataMember]
public virtual StagComplaint Complaint { get; set; }
public int ComplaintID { get; set; }
public virtual Role Role { get; set; }
public int RoleID { get; set; }
public StagActor() {
this.Emails = new List<StagEmail>();
this.Phones = new List<StagPhone>();
this.Address = new StagAddress();
}
}
public class ActorBase : BORBase {
public string Name { get; set; }
}
public class StagRectification : BORBase {
public bool Active { get; set; }
public string Notes { get; set; }
public virtual RectificationType RectificationType { get; set; }
public int RectificationTypeID { get; set; }
[IgnoreDataMember]
public virtual StagComplaint Complaint { get; set; }
public int ComplaintID { get; set; }
}
This is the client side code I am using to create the Complaint:
public int AddParcelsToStagingComplaint(List<string> parcelIDs, string userID) {
StagComplaint comp = new StagComplaint();
int Result = 0;
using (BORServiceClient db = new BORServiceClient()) {
comp = new StagComplaint() {
BuildingValue = 111222,
Category = "*",
LandValue = 222333,
Number = "*",
TaxYear = DateTime.Now.Year,
ComplaintTypeID = 1,
UserIdentification = userID,
CreationDate = DateTime.Now,
};
StagAddress ca = new StagAddress() { Line1 = "670 Harvard Blvd", City = "Cleveland", State = "OH", ZipCode = "44113", };
List<StagPhone> ps = new List<StagPhone>();
ps.Add(new StagPhone() { Number = "5556664646", Type = PhoneTypes.Home, UserIdentification = userID, CreationDate = DateTime.Now, });
comp.Actors.Add(
new StagActor() {
Name = "Joe Schmoe",
Address = ca,
Phones = ps,
RoleID = 1,
UserIdentification = userID,
CreationDate = DateTime.Now,
}
);
StagAddress aa = new StagAddress() {
City = wp.Address.City,
Line1 = wp.Address.Line1,
Line2 = wp.Address.Line2,
State = wp.Address.State,
ZipCode = wp.Address.ZipCode,
};
ps = new List<StagPhone>();
ps.Add(new StagPhone() { Number = "4448887878", Type = PhoneTypes.Work, UserIdentification = userID, CreationDate = DateTime.Now, });
StagParcel p = new StagParcel() {
Address = new StagAddress() { Line1 = "4 Oxford Drive", City = "Hudson", State = "OH", ZipCode = "44236" },
BuildingValue = wp.BuildingValue,
LandUseCode = wp.LandUseCode,
LandValue = wp.LandValue,
NeighborhoodCode = wp.NeighborhoodCode,
Number = wp.Number,
Owner = new StagActor() { Name = "Owner Person", Address = aa, RoleID = 2, Phones = ps, UserIdentification = userID, CreationDate = DateTime.Now, },
OwnerOpinion = wp.OwnerOpinion,
SchoolBoardID = wp.SchoolBoardID,
SchoolDistrict = wp.SchoolDistrict,
TaxDistrict = wp.TaxDistrict,
UserIdentification = userID,
CreationDate = DateTime.Now,
};
comp.Parcels.Add(p);
ServiceResponse<int> saved = db.AddComplaint((ComplaintBase)comp, Contexts.Staging, userID);
if (saved.WasSuccessful)
Result = saved.Result;
} // using the database
return Result;
} // AddParcelsToStagingComplaint - Method
Here is the WCF method that gets called:
using (StagComplaintRepo cr = new StagComplaintRepo()) {
cr.Add((StagComplaint)complaint, userID);
if (cr.Save()) {
Result.Result = complaint.ID;
Result.WasSuccessful = true;
} else {
Result.AddException(string.Format("Unable to create a new Complaint in the {0} context.", context));
} // if the save was successful
} // using the Complaint Repository
And here is the BaseRepository that has the Save and Add methods:
public abstract class BaseRepository<T> : IDisposable, IRepository<T> where T : class {
public virtual bool Save(bool detectChanges = false) {
if (detectChanges == true)
this.Entities.ChangeTracker.DetectChanges();
return (this.Entities.SaveChanges() > 0);
}
public virtual void Add(T entity, string userID) {
this.Entities.Set<T>().Add(entity);
}
...
}
It fails on the above this.Entities.SaveChanges() call with the error mentioned at the top of this post. There is no extra inner exception. If I only fill in the Complaint properties that are required and are part of that object, it works. But once I add a Parcel with an Actor it fails.
I assume it is something simple, perhaps a switch needs to be turned on or off. But similar errors all seem to reference AcceptChanges and that is not the issue here. At least based on the error message. Any help would be appreciated.
EDIT
Here is the full stack trace:
at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)
at System.Data.Entity.Internal.InternalContext.SaveChanges()
at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
at System.Data.Entity.DbContext.SaveChanges()
at BOR.WebService.Repositories.BaseRepository`1.Save(Boolean detectChanges) in d:\DevProjects\BOR\WebService\Main\Source\WebServiceSolution\WcfServiceProject\Repositories\BaseRepository.cs:line 22
at BOR.WebService.BORService.AddComplaint(ComplaintBase complaint, Contexts context, String userID) in d:\DevProjects\BOR\WebService\Main\Source\WebServiceSolution\WcfServiceProject\BORService.svc.cs:line 65
Line 22 is:
return (this.Entities.SaveChanges() > 0);
Line 65 is:
if (cr.Save()) {
I created this viewmodel:
public class PlayerViewModel
{
PlayerRepository repo = new PlayerRepository();
public Player Player { get; set; }
public int SelectedUserID { get; set; }
public SelectList Users { get; set; }
public PlayerViewModel()
{
Player = new Player();
}
public PlayerViewModel(int id)
{
Player = repo.Retrieve(id);
Users = new SelectList(repo.GetUsers());
SelectedUserID = 0;
}
}
this I have in view:
#Html.DropDownListFor(x => x.SelectedUserID, Model.Users)
#Html.ValidationMessageFor(x => x.SelectedUserID)
and this in controller:
[Authorize]
public ActionResult Upravit(int id)
{
var playerview = new PlayerViewModel(id);
return View(playerview);
}
[Authorize,HttpPost]
public ActionResult Upravit(int id, PlayerViewModel playerView)
{
if (ModelState.IsValid)
{
playerView.Player.User = usRepo.GetUserById(playerView.SelectedUserID);
repo.Save(playerView.Player);
return RedirectToAction("Podrobnosti", new { id = playerView.Player.PlayerID });
}
return View(playerView);
}
Now I have problem that " The field SelectedUserID must be a number." and I have in dropdownlist UserName. I modified this many times, I tried with Dictionary and other ways but everyway has some problem. So I want just ask for best way to add custom class User to class Player.
Player class:
public class Player
{
// pokud použijeme virtual a vlastností tak nám EF rozšíří o další možnosti jako lazy loading a další
[Key]
public int PlayerID { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Surname { get; set; }
public string PhotoUrl { get; set; }
public string Post { get; set; }
public virtual Team Team { get; set; }
public virtual User User { get; set; }
// public int UserID { get; set; }
//public virtual ICollection<Article> Articles { get; set; }
// Here could be next things as number, ...
}
Thanks
Use this constructor instead:
http://msdn.microsoft.com/en-us/library/dd505286.aspx
public SelectList(
IEnumerable items,
string dataValueField,
string dataTextField
)
Something like this:
Users = new SelectList(repo.GetUsers(),"UserID", "UserName");