Entity Framework – How to add db entries without a form

Usually I add new database entries with a “Create” form, just like the template you are given like this:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "MyObjectProperties")] MyObject MyObjectName)
{
    if (ModelState.IsValid)
    {
        db.MyObjects.Add(MyObjectName);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    return View(MyObjectName);
}

Which works just fine. However, I’m trying to delete all entries in my database and then add them again one by one. The purpose is that the table is filled with deadline dates for each week in a year, and this method will reset the deadlines and set the correct dates for the given year. This is the method that performs that task:
public bool ResetDeadlines()
{
    //db.Canteen_Deadlines.RemoveRange(db.Canteen_Deadlines);

    int monthOfLastWeek = 1;
    DateTime deadlineDate;
    int weekOfMonth = 0;
    int year = DateTime.Now.Year;

    for (var i = 1; i < 53; i++)
    {
        if (i == 1)
            year += 1;
        else
            year = DateTime.Now.Year;

        deadlineDate = GetThursdayOfWeek(year, i).AddDays(-7); //Gets the thursday of the week before, because that is the deadline for that week.
        weekOfMonth = monthOfLastWeek < deadlineDate.Month ? 1 : weekOfMonth + 1;

        var newDeadline = new Canteen_Deadlines
        {
            N = DaysFromNewYear(year, deadlineDate),
            DeadlineDate = deadlineDate,
            WeekNo = (byte)i,
            MonthNo = (byte)deadlineDate.Month,
            QuarterNo = (byte)GetQuarterNumber(deadlineDate.Month),
            YearNo = (short)year,
            DayofWeek = 4,
            LastDowInMonth = IsLastDoWInMonth(deadlineDate),
            DoWAsc = (byte)weekOfMonth
        };

        db.Canteen_Deadlines.Add(newDeadline);
        //db.Entry(newDeadline).State = EntityState.Added;
        db.SaveChanges();

        monthOfLastWeek = deadlineDate.Month;
    }

    return true;
}

The problem arises when I do db.SaveChanges();. It will give me a DbUpdateConcurrencyException, saying that none of the rows in the database has been affected. I can’t seem to figure out the difference between my method and the template create method. Other posts online are more focused on this problem arising when using the template create method and people not using “Html.HiddenFor” on their ID. This is not a viable solution for me, since I am not using a form and therefore have no way of using the Html helper. The user will just press a “Reset deadlines” button.

The “N” property on the objects are their keys. It is the amount of days the given date is into the year, meaning 16th of January would be N = 16. As the deadlines only are for 1 year, the N values will not conflict and therefore should be able to be used as keys.

How can I save these entries in the database successfully? I have commented out the db.remove method, just to get the adding of entries to work. I have also tried setting the entry states to added, but that did not work either. I tried debugging and confirmed that all properties of the object is initialized correctly.

Full exception:

[OptimisticConcurrencyException: Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions.]
   System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.ValidateRowsAffected(Int64 rowsAffected, UpdateCommand source) +142
   System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update() +525
   System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction(Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess) +453
   System.Data.Entity.Core.Objects.ObjectContext.SaveChangesToStore(SaveOptions options, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction) +252
   System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute(Func`1 operation) +206
   System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal(SaveOptions options, Boolean executeInExistingTransaction) +270
   System.Data.Entity.Internal.InternalContext.SaveChanges() +145

[DbUpdateConcurrencyException: Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions.]
   System.Data.Entity.Internal.InternalContext.SaveChanges() +280
   MyProject.Models.Services.DeadlinesService.ResetDeadlines() in \PROJECTPATHModelsServicesDeadlinesService.cs:49
   MyProject.Controllers.AdminController.ResetDeadlines() in \PROJECTPATHControllersAdminController.cs:254
   lambda_method(Closure , ControllerBase , Object[] ) +87
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +35
   System.Web.Mvc.Async.<>c.<BeginInvokeSynchronousActionMethod>b__9_0(IAsyncResult asyncResult, ActionInvocation innerInvokeState) +39
   System.Web.Mvc.Async.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult) +77
   System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) +42
   System.Web.Mvc.Async.<>c__DisplayClass11_0.<InvokeActionMethodFilterAsynchronouslyRecursive>b__0() +80
   System.Web.Mvc.Async.<>c__DisplayClass11_2.<InvokeActionMethodFilterAsynchronouslyRecursive>b__2() +387
   System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult) +42
   System.Web.Mvc.Async.<>c__DisplayClass3_6.<BeginInvokeAction>b__4() +50
   System.Web.Mvc.Async.<>c__DisplayClass3_1.<BeginInvokeAction>b__1(IAsyncResult asyncResult) +188
   System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +38
   System.Web.Mvc.<>c.<BeginExecuteCore>b__152_1(IAsyncResult asyncResult, ExecuteCoreState innerState) +26
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +73
   System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +52
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +39
   System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +38
   System.Web.Mvc.<>c.<BeginProcessRequest>b__20_1(IAsyncResult asyncResult, ProcessRequestState innerState) +40
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +73
   System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +38
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +602
   System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step) +195
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +128

EDIT:
Controller Action:
public ActionResult ResetDeadlines()
        {
            deadlinesService.ResetDeadlines();

            return RedirectToAction("IndexDeadlines");
        }

View:
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <div class="row" style="margin-left:0px">
            <div>
                <label for="SearchInput" style="font-size:18px">@Res.Search @Res.Week</label>
                @Html.Editor("Search", new { htmlAttributes = new { @class = "form-control", @autofocus = "autofocus", @id = "SearchInput", @onkeyup = "myFunction()" } })
            </div>
            <div style="margin-left:10px;margin-top:18px">
                <a href="@Url.Action("ResetDeadlines")" class="customBtnXSmall">Reset Deadlines</a>
            </div>
        </div>
    </div>
}

This is the Deadline class:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Web;

namespace MyProject.Models.DBModels
{
    public class Canteen_Deadlines
    {
        [Key]
        public long? N { get; set; } //Number of days into the year (16th of January is 16 days into the year, so N would be = 16)
        [Column(TypeName = "smalldatetime")]
        public DateTime? DeadlineDate { get; set; }
        public byte? WeekNo { get; set; }
        public byte? MonthNo { get; set; }
        public byte? QuarterNo { get; set; }
        public short YearNo { get; set; }
        public byte? DayofWeek { get; set; }
        public bool? LastDowInMonth { get; set; } //Last DayOfWeek In Month
        public byte? DoWAsc { get; set; } //DayOfWeek Ascending
    }
}

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Try to use this code:

.....

var deadlines=new List<PP_CanteenScreen_Deadlines>();

for (var i = 1; i < 53; i++)
 {
                if (i == 1)
                    year += 1;
                else
                    year = DateTime.Now.Year;

                deadlineDate = GetThursdayOfWeek(year, i).AddDays(-7); //Gets the thursday 
              //of the week before, because that is the deadline for that week.
                weekOfMonth = monthOfLastWeek < deadlineDate.Month ? 1 : weekOfMonth + 1;

                var newDeadline = new PP_CanteenScreen_Deadlines
                {
                    N = DaysFromNewYear(year, deadlineDate),
                    DeadlineDate = deadlineDate,
                    WeekNo = (byte)i,
                    MonthNo = (byte)deadlineDate.Month,
                    QuarterNo = (byte)GetQuarterNumber(deadlineDate.Month),
                    YearNo = (short)year,
                    DayofWeek = 4,
                    LastDowInMonth = IsLastDoWInMonth(deadlineDate),
                    DoWAsc = (byte)weekOfMonth
                };
                deadlines.Add(newDeadline);
               monthOfLastWeek = deadlineDate.Month;

}
                db.PP_CanteenScreen_Deadlines.AddRange(deadlines);
               var result=  db.SaveChanges();
              if(result < 52) .....your error code

........

And I am wondering why you don’t try to use auto-increment primary key instead of
public long? N ? Especially I don’t like that your primary key is nullable. Is there some reasons for this?

Method 2

After numerous attempts to locate the real issue and with a lot of assistance from @Sergey, I realized that the underlying issue was due to the design of the table in the database and the way Entity Framework 6 works.

SOLUTION:

I added a property ID to the Canteen_Deadlines class in my code, which is now the key, and added a corresponding column in the database table designer. EF6 now understands that I’m adding new rows and lets the database table assign IDs, so I can assign my own N values.

BACKGROUND:

EF6 kept acting like I was trying to update my rows, since N was my key in EF6, which would make sense if it was not for the fact that I’m trying to add rows. Using Microsoft documentation to do a Try-Catch on the UpdateConcurrencyException confirmed that it was trying to update rows, but could not do it when I’m actually adding them (the new exception was saying that the catch logic would not work with entities in an “added” state).


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x