0

so in my person table...I have Id, Name & HolidaysRemaining.

Its for a holiday booking application, and atm when a user selects dates from a calendar and clicks the button, each date selected will be stored in the DB, I am trying to minus the holidays remaining by 1, as each holiday is booked, but it doesn't seem to be picking up.

//listHolidays in correct format dd/mm/yy
    [HttpPost]
    public ActionResult listHolidays(Holiday holiday, Person person , int? PersonId, string HolidayDate, string endDate, string AlreadyExists)
    {
        db.People.Attach(person);
        //int holidaysRemaining = 20;
        //person.HolidaysRemaining = holidaysRemaining;    

        DateTime startDates = Convert.ToDateTime(HolidayDate);
        DateTime endDates = Convert.ToDateTime(endDate);

    try{

        while (startDates <= endDates)
        {
            if (startDates.DayOfWeek != DayOfWeek.Saturday && startDates.DayOfWeek != DayOfWeek.Sunday)
            {                 
                //if user selects Holiday that already exists, wont add it to Db
                //gets string, and uses the previously converted to dateTime 'startDate'
                //id so only applies to person creating holidays
                ViewBag.CantDuplicateHolidays = String.IsNullOrEmpty(AlreadyExists) ? "date" : "";
                var dates = from d in db.Holidays
                where d.HolidayDate == startDates && d.PersonId == PersonId
                select d;

                // <= 0..so if holiday does not already exist
                if (dates.Count() <= 0)
                {
                  //  holidaysRemaining--;
                    person.HolidaysRemaining = person.HolidaysRemaining - 1;

                    Holiday holiday1 = new Holiday();
                    holiday1.PersonId = PersonId.Value;
                    holiday1.HolidayDate = startDates;

                    db.Holidays.AddObject(holiday1);


                    db.SaveChanges();
                    //say start date is 10. AddDays(1) will make it 11 then return it to startDates in 'startDates' = startdates,
                    //but doesnt chage the value of startdates = 'startdates'
                }

            }
        }

        startDates = startDates.AddDays(1);
    }


    finally
    {
        db.People.Detach();
    }

    return RedirectToAction("Index");
}
John
  • 3,965
  • 21
  • 77
  • 163
  • try setting person.HolidaysRemaining-- to person.HolidaysRemaining = person.HolidaysRemaining--; – Alex Dec 13 '12 at 16:58
  • Have you tried setting a breakpoint at this line `if (dates.Count() <= 0)`? Stepping through it for both true and false of the if would probably be helpful. –  Dec 13 '12 at 17:06
  • thanks for the reply, iv tried 'setting person.HolidaysRemaining-- to person.HolidaysRemaining = person.HolidaysRemaining--;'and no joy, iv added in breakpoints, tested booking 2 holidays, after it runs through the loop twice holidaysRemaining has a value of '-2' but it doesnt seem to update this to the actual db...any advise? – John Dec 13 '12 at 17:12
  • 1
    Why would it update -2 to the DB? You never update person in the db object. e.g. `db.UpdateObject(person);` See: http://stackoverflow.com/questions/3920111/entity-framework-4-addobject-vs-attach –  Dec 13 '12 at 17:14
  • thanks I tried this but... db.UpdateObject(person); is telling me it does not contain a defination for 'updateobject'?? please advise thank you – John Dec 13 '12 at 17:48
  • `db.People.Detach(person);` note: Convert.ToDateTime() can throw exception. Also, it isn't clear what `db` is defined as, we've been basically guessing. –  Dec 13 '12 at 19:44

2 Answers2

1

I think your problem is here:

if (dates.Count() <= 0)
    {
    //  holidaysRemaining--;
    person.HolidaysRemaining--;

Try changing it to:

if (dates.Count() <= 0)
    {
    //  holidaysRemaining--;
    person.HolidaysRemaining = person.HolidaysRemaining - 1;

EDIT

Also, you never actually update the database with person?

db.People.Attach(person);

before db.SaveChanges();

EDIT AGAIN

Try this:

[HttpPost] public ActionResult listHolidays(Holiday holiday, Person person, int? PersonId, string HolidayDate, string endDate, string AlreadyExists) {
//int holidaysRemaining = 20; //person.HolidaysRemaining = holidaysRemaining;

        DateTime startDates = Convert.ToDateTime(HolidayDate);
        DateTime endDates = Convert.ToDateTime(endDate);

        while (startDates <= endDates)
        {
            if (startDates.DayOfWeek != DayOfWeek.Saturday && startDates.DayOfWeek != DayOfWeek.Sunday)
            {                 
                    //if user selects Holiday that already exists, wont add it to Db
                    //gets string, and uses the previously converted to dateTime 'startDate'
                    //id so only applies to person creating holidays
                    ViewBag.CantDuplicateHolidays = String.IsNullOrEmpty(AlreadyExists) ? "date" : "";
                    var dates = from d in db.Holidays
                    where d.HolidayDate == startDates && d.PersonId == PersonId
                    select d;

                    // <= 0..so if holiday does not already exist
                    if (dates.Count() <= 0)
                    {
                      //  holidaysRemaining--;
                        person.HolidaysRemaining = person.HolidaysRemaining - 1;

                        Holiday holiday1 = new Holiday();
                        holiday1.PersonId = PersonId.Value;
                        holiday1.HolidayDate = startDates;

                        db.Holidays.AddObject(holiday1);
            db.People.Attach(person);

                        db.SaveChanges();
                        //say start date is 10. AddDays(1) will make it 11 then return it to startDates in 'startDates' = startdates,
                        //but doesnt chage the value of startdates = 'startdates'
                    }

            }

            startDates = startDates.AddDays(1);
        }

        return RedirectToAction("Index");
    }
Alex
  • 37,502
  • 51
  • 204
  • 332
  • Thanks for the reply..basically same as I have just said above – John Dec 13 '12 at 17:12
  • You never attach your person changes to the context. See my edit – Alex Dec 13 '12 at 17:16
  • 1
    I think you're probably looking for: `db.Person.Attach(person);` –  Dec 13 '12 at 17:20
  • ok thanks guys..i tried db.Person.AddObject(personThe object cannot be attached because it is already in the object context. An object can only be reattached when it is in an unchanged state.); and it wouldnt work, the error came from this line and said: – John Dec 13 '12 at 17:35
  • I also tried db.Person.AddObject(person); and it wouldnt allow me I had to write. db.People.AddObject(person);...i guess this is because of the one to many r/s between person and holiday?? so I used Person person1 = new Person(); db.People.AddObject(person1); this throws an error with:db.SaveChanges(); stating:{"Cannot insert the value NULL into column 'Name', table 'holidays.dbo.Person'; column does not allow nulls. INSERT fails.\r\nThe statement has been terminated."}....what is being inserted as Null, i have a name and dates selected, why is null being passed? – John Dec 13 '12 at 17:42
  • @John see the edited answer - i've sorted out pluralization (Person / People) and as per ebyrob comment, changed to Attach – Alex Dec 13 '12 at 18:03
  • @alexjamesbrown Thanks for taking the time to help me with this...hbut I've added Person person1 = new Person(); & db.People.Attach(person1);...it is throwing me an error with people.attach saying : An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key....any advice? – John Dec 13 '12 at 18:23
  • @ebyrob i'v tried that but no joy(see above) thanks for helping but do you have any ideas? – John Dec 13 '12 at 18:23
  • Why are you creating, then adding person1? you need to attach person (as passed in from the controller)... Have added code, try that – Alex Dec 13 '12 at 18:25
  • oh, right. Either re-attach the person object only once at the top of the method outside the loop. -or- look up an already attached person object with data in the passed in person object and modify that. –  Dec 13 '12 at 18:29
  • @alexjamesbrown thank you for that, but db.People.Attach(person); is throwing an error with :Invalid operation exception was unhandled by the user code..............The object cannot be attached because it is already in the object context. An object can only be reattached when it is in an unchanged state. – John Dec 13 '12 at 18:35
  • @alexjamesbrown EDIT---So i done a bit of testing, I added a new user and so far, if the user attempts to book a new holiday date, which has previously been booked by them it will throw that error, also if they are bookin more than 1 day it throws this error. I can however book one day at a time, but the holidaysRemaining remains at 20....any guess guys? Thanks – John Dec 13 '12 at 18:43
  • @ebyrob Iv changed the position of db.People.Attach(person); to the first line of the method(outside the loop) its now throwing me the error: OptimisticConcurrentException was unhandled by user code: Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.....why is this happening? please advise...thanks again – John Dec 13 '12 at 19:00
  • If this object store is persistent and you're doing more than one operation, you'll want to .Detach() at the end of the method (probably in a finally {}). And you may need to lock() {}. –  Dec 13 '12 at 19:06
  • @ebyrob what am i putting in the try? iv edited my original post to the code i have atm. thanks again for the reply – John Dec 13 '12 at 19:13
  • everything after the .Attach() that might fail should go in the try {} –  Dec 13 '12 at 19:19
  • @ebyrob iv put the while look inside the try, I am getting 'no overload methods for detach' please see my new edit....sorry about this, what do I need to do?thanks again much appreciated – John Dec 13 '12 at 19:27
1

Probably this is the easiest solution.

replace:

person.HolidaysRemaining = person.HolidaysRemaining - 1;

with:

var dbPerson = from p in db.People where p.Id == PersonId select p;
dbPerson[0].HolidaysRemaining--;

Alternatively we were discussing attaching the person object since you have it:

    db.People.Attach(person)
    try {
        // ... loop and everything else here
    } finally {
        db.People.Detach(person);
    }
} // end of method

But this is a bit more brittle, and would only be necessary if there's not already a Person object in db.People.

Note: It seems a little weird that both person and PersonId are passed into listHolidays().

  • I got it going but had to change the last line to dbPerson.Single().HolidaysRemaining--; Thank you very much for taking the time to help me with this, much appreciated @ebyrob – John Dec 14 '12 at 13:38