2

Invoice Category Entity:

public class InvoiceCategory
{     
    [Key]
    Public int InvoiceCategoryID { get; set; }

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

Invoice Item Entity

public class InvoiceItem
{
    [Key]
    public int InvoiceItemID { get; set; }

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

    [Required]
    [Display(Name = "Date Completed")]
    [DataType(DataType.Date)] 
    public DateTime? Date { get; set; }

    [StringLength(50)]
    public string InvoiceCategory { get; set; }  

    [Required]
    [StringLength(200)]
    public string Description { get; set; }

    [Required]
    [StringLength(20)]
    public string Unit { get; set; }     

    [Required]
    [DataType(DataType.Currency)]
    [DisplayFormat(ApplyFormatInEditMode = false, DataFormatString = "{0:c}")]
    public decimal Price { get; set; }

    [Required]
    [DefaultValue(1)]
    public decimal? Quantity { get; set; }

    public virtual Invoice Invoice { get; set; }       
}

Invoice Category Edit View

@model Accounts.Models.InvoiceCategory
<h2>Settings</h2>
<br />
<h4>Invoice Categories</h4>
<hr />
<form asp-action="Edit">
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    @(Html.Kendo().Grid<Accounts.Models.InvoiceCategory>()
              .Name("InvoiceCategory")
              .ToolBar(tools =>
              {
                  tools.Create().Text("New Category");
              })
              .Editable(editable => editable.Mode(GridEditMode.InCell).CreateAt(GridInsertRowPosition.Bottom).DisplayDeleteConfirmation(false))
              .Columns(columns =>
              {
                  columns.Bound(p => p.InvoiceCategoryID).Hidden().ClientTemplate("#= InvoiceCategoryID #" +
                    "<input type='hidden' name='[#= index(data)#].InvoiceCategoryID' value='#= InvoiceCategoryID #'/>"
                  );

                  columns.Bound(p => p.CategoryName).ClientTemplate("#= CategoryName #" +
                    "<input type='hidden' name='[#= index(data)#].CategoryName' value='#= CategoryName #'/>"
                  );
                  columns.Template("<a class='btn btn-danger btn-sm k-grid-delete'><span class='glyphicon glyphicon-trash'></span> </a>").Width(50);
              })
              .DataSource(dataSource => dataSource.Ajax()
                   .Model(model =>
                   {
                       model.Id(p => p.InvoiceCategoryID);
                       model.Field(p => p.InvoiceCategoryID).Editable(false);
                   })
                   .Read(read => read.Action("InvoiceCategories_Read", "Settings"))                       
                   .ServerOperation(false)
              ).Deferred()
    )
    <br />
    <button type="submit" class="btn btn-success"><span class="glyphicon glyphicon-floppy-disk" style="vertical-align:middle;margin-top:-5px"></span> Save</button>
</form>
@section Scripts {
    @Html.Kendo().DeferredScripts()

    <script>
        function index(dataItem) {
            var data = $("#InvoiceCategory").data("kendoGrid").dataSource.data();
            return data.indexOf(dataItem);
        }
    </script>

    <style>
        .k-grid {
            width: 280px;
        }
    </style>
}

Controller Invoice Category Update Method:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(IEnumerable<InvoiceCategory> invoiceCategory)
{
    if (ModelState.IsValid)
    {
        try
        {
            _context.InvoiceCategory.UpdateRange(invoiceCategory);
            _context.SaveChangesAsync();
        }
        catch (Exception ex)
        {
           ...
        }
    }
}

The values are being changed in the view and the changes are being sent to the Edit method of the controller however the changes are not promulgated to the database for some reason with the save method.

Can Entity framework not support a lookup table with no integer identity column like I have? Or am I doing something stupid?

1 Answer 1

4

Essentially that you are trying to do is to update the Primary Key of the table called InvoiceCategory. Irrespectively, with the context of your code, if you think about it in the context of databses, this does not make sense. A Primary Key is the unique identifier of a record. You shouldn't be able to update it.

As a side note, whenever you use async you should use at least one use await. Otherwise your method would be executed synchronously. In your case the missing await is this:

await _context.SaveChangesAsync();

Update

I think that you need is something along the following lines:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(IEnumerable<InvoiceCategory> invoiceCategories)
{
    if (ModelState.IsValid)
    {
        try
        {
            foreach(var invoiceCategory in invoiceCategories)
            {
                if(invoiceCategory.InvoiceCategoryID == 0)
                {
                    _context.InvoiceCategory.Add(invoiceCategory);    
                }
                else
                {
                    _context.InvoiceCategory.Update(invoiceCategory);
                }
            }
            await _context.SaveChangesAsync();
        }
        catch (Exception ex)
        {
           ...
        }
    }
}
Sign up to request clarification or add additional context in comments.

7 Comments

+1 Thanks Christos. So I understand what I am trying to do is not possible and I need to add an int identity column to the lookup table?
So I have added an identity column to the lookup table (InvoiceCategoryID) and still the database is not updated. I'm not sure I am using updaterange correctly.
@Reafidy you are welcome. Could you please post a diagram with the schema of your DB (only the tables related InvoiceCategory)? Also it would be very helpful, if you could desribe a use case, in order to understan d what you have and what you want to achieve. Thanks in advance !
The InvoiceCategory is a category for the InvoiceItem entity, such as Accommodation, Travel, Parts etc. It is purely a predefined lookup column that will be used in the InvoiceItem entity so a user can select a category if they want it or enter a completely new one not in the list. As the user will be able to enter any category and not just from the list it will be stored as text in the InvoiceItem entity so I wont use an ID column to link it. So it really has no related tables, purely a lookup. So at the moment I just want to create a page & controller to edit the InvoiceCategory values.
I have edited my original post to include the new InvoiceCategory model with Autogenerated ID column, plus I have shown the InvoiceItem entity and the View to edit the InvoiceCategory.
|

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.