2011-12-09 20 views
0

私はMVC3を初めて使用し、簡単な請求書作成アプリケーションを構築しようとしています。私のコードの問題は、Ajax Postが失敗していて、なぜそれが見つからないということです。 JQueryコードを踏んだところ、POSTがコントローラにヒットした時点でModel.IsValidがfalseになります。問題は子供の記録と思われる。請求書マスタレコードがDBに保存されていますが、InvoiceRowは保存されていません。問題は、SaveInvoice()関数にあります。Asp.Net MVC 3(Razor、Json、Ajax)マスターディテール - ディテールセーブ失敗

public class Invoice 
{ 
    [Key] 
    public int InvoiceID { get; set; } 

    public int ContractID { get; set; } 

    [Required] 
    [Display(Name = "Invoice Date")] 
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd MMM yyyy}")] 
    public DateTime InvoiceDate { get; set; } 

    [Required] 
    [Display(Name = "Invoice No")] 
    public int InvoiceNumber { get; set; } 

    [Required(AllowEmptyStrings = true)] 
    [Display(Name = "Payment Date")] 
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd MMM yyyy}")] 
    public DateTime PaymentDate { get; set; } 

    public virtual Contract Contract { get; set; } 

    public virtual ICollection<InvoiceRow> InvoiceRows { get; set; } 
} 

public class InvoiceRow 
{ 
    [Key] 
    public int Id { get; set; } 
    public int InvoiceID { get; set; } 
    public string RowDetail { get; set; } 
    public int RowQty { get; set; } 
    public decimal ItemPrice { get; set; } 
    public decimal RowTotal { get; set; } 

    public virtual Invoice Invoice { get; set; } 
} 


public class InvoiceController : Controller 
{ 
    private CyberneticsContext db = new CyberneticsContext(); 

    // 
    // GET: /Invoice/ 

    public ViewResult Index() 
    { 
     var invoices = db.Invoices.Include(i => i.Contract); 
     return View(invoices.ToList()); 
    } 

    // 
    // GET: /Invoice/Details/5 

    public ViewResult Details(int id) 
    { 
     Invoice invoice = db.Invoices.Find(id); 
     return View(invoice); 
    } 

    // 
    // GET: /Invoice/Create 

    public ActionResult Create() 
    { 
     ViewBag.Title = "Create"; 
     ViewBag.ContractID = new SelectList(db.Contracts, "Id", "ContractName"); 
     return View(); 
    } 

    // 
    // POST: /Invoice/Create 

    [HttpPost] 
    public JsonResult Create(Invoice invoice) 
    { 
     try 
     { 
      if (ModelState.IsValid) 
      { 
       if (invoice.InvoiceID > 0) 
       { 
        var invoiceRows = db.InvoiceRows.Where(ir => ir.InvoiceID == invoice.InvoiceID); 

        foreach (InvoiceRow row in invoiceRows) 
        { 
         db.InvoiceRows.Remove(row); 
        } 

        foreach (InvoiceRow row in invoice.InvoiceRows) 
        { 
         db.InvoiceRows.Add(row); 
        } 

        db.Entry(invoice).State = EntityState.Modified; 
       } 
       else 
       { 
        db.Invoices.Add(invoice); 
       } 

       db.SaveChanges(); 

       return Json(new { Success = 1, InvoiceID = invoice.InvoiceID, ex = "" }); 
      } 

     } 
     catch (Exception ex) 
     { 
      return Json(new { Success = 0, ex = ex.Message.ToString() }); 
     } 

     return Json(new { Success = 0, ex = new Exception("Unable to Save Invoice").Message.ToString() }); 
    } 

    // 
    // GET: /Invoice/Edit/5 

    public ActionResult Edit(int id) 
    { 
     ViewBag.Title = "Edit"; 
     Invoice invoice = db.Invoices.Find(id); 
     ViewBag.ContractID = new SelectList(db.Contracts, "Id", "ContractName", invoice.ContractID); 
     return View("Create", invoice); 
    } 

    // 
    // POST: /Invoice/Edit/5 

    [HttpPost] 
    public ActionResult Edit(Invoice invoice) 
    { 
     if (ModelState.IsValid) 
     { 
      db.Entry(invoice).State = EntityState.Modified; 
      db.SaveChanges(); 
      return RedirectToAction("Index"); 
     } 
     ViewBag.ContractID = new SelectList(db.Contracts, "Id", "ContractName", invoice.ContractID); 
     return View(invoice); 
    } 

    // 
    // GET: /Invoice/Delete/5 

    public ActionResult Delete(int id) 
    { 
     Invoice invoice = db.Invoices.Find(id); 
     return View(invoice); 
    } 

    // 
    // POST: /Invoice/Delete/5 

    [HttpPost, ActionName("Delete")] 
    public ActionResult DeleteConfirmed(int id) 
    { 
     Invoice invoice = db.Invoices.Find(id); 
     db.Invoices.Remove(invoice); 
     db.SaveChanges(); 
     return RedirectToAction("Index"); 
    } 

    protected override void Dispose(bool disposing) 
    { 
     db.Dispose(); 
     base.Dispose(disposing); 
    } 
    } 
} 

@model Cybernetics2012.Models.Invoice 

... script tags excluded for brevity 

<h2 class="h2">@ViewBag.Title</h2> 


<script type="text/javascript"> 

$(document).ready(function() 
{ 
    // here i have used datatables.js (jQuery Data Table) 
    $('.tableItems').dataTable 
    ( 
     { 
      "sDom": 'T<"clear">lfrtip', 
      "oTableTools": { "aButtons": [], "sRowSelect": "single" }, 
      "bLengthChange": false, 
      "bFilter": false, 
      "bSort": true, 
      "bInfo": false 
     } 
    ); 

    // Add DatePicker widget to InvoiceDate textbox 
    $('#InvoiceDate').datepicker(); 

    // Add DatePicker widget to PaymentDate textbox 
    $('#PaymentDate').datepicker(); 

    // Get the tableItems table 
    var oTable = $('.tableItems').dataTable(); 
}); 


// this function is used to add item to table 
function AddInvoiceItem() 
{ 
    // Adding item to table 
    $('.tableItems').dataTable().fnAddData([$('#RowDetail').val(), $('#RowQty').val(), $('#ItemPrice').val(), $('#RowQty').val() * $('#ItemPrice').val()]); 

    // clear text boes after adding data to table.. 
    $('#RowDetail').val("") 
    $('#RowQty').val("") 
    $('#ItemPrice').val("") 

} 


// This function is used to delete selected row from Invoice Rows Table and then set deleted item to Edit text Boxes 
function DeleteRow() 
{ 
    // DataTables.TableTools plugin for getting selected row items 
    var oTT = TableTools.fnGetInstance('tableItems'); // Get Table instance 
    var sRow = oTT.fnGetSelected(); // Get Selected Item From Table 

    // Set deleted row item to editable text boxes 
    $('#RowDetail').val($.trim(sRow[0].cells[0].innerHTML.toString())); 
    $('#RowQty').val(jQuery.trim(sRow[0].cells[1].innerHTML.toString())); 
    $('#ItemPrice').val($.trim(sRow[0].cells[2].innerHTML.toString())); 

    $('.tableItems').dataTable().fnDeleteRow(sRow[0]); 
} 


//This function is used for sending data(JSON Data) to the Invoice Controller 
function SaveInvoice() 
{ 
    // Step 1: Read View Data and Create JSON Object 

    // Creating invoicRow Json Object 
    var invoiceRow = { "InvoiceID": "", "RowDetail": "", "RowQty": "", "ItemPrice": "", "RowTotal": "" }; 

    // Creating invoice Json Object 
    var invoice = { "InvoiceID": "", "ContractID": "", "InvoiceDate": "", "InvoiceNumber": "", "PaymentDate": "", "InvoiceRows":[] }; 

    // Set Invoice Value 
    invoice.InvoiceID = $("#InvoiceID").val(); 
    invoice.ContractID = $("#ContractID").val(); 
    invoice.InvoiceDate = $("#InvoiceDate").val(); 
    invoice.InvoiceNumber = $("#InvoiceNumber").val(); 
    invoice.PaymentDate = $("#PaymentDate").val(); 

    // Getting Table Data from where we will fetch Invoice Rows Record 
    var oTable = $('.tableItems').dataTable().fnGetData(); 

    for (var i = 0; i < oTable.length; i++) 
    { 

     // IF This view is for edit then it will read InvoiceId from Hidden field 
     if ($('h2').text() == "Edit") 
     { 
      invoiceRow.InvoiceID = $('#InvoiceID').val(); 
     } 
     else 
     { 
      invoiceRow.InvoiceID = 0; 
     } 

     // Set InvoiceRow individual Value 
     invoiceRow.RowDetail = oTable[i][0]; 
     invoiceRow.RowQty = oTable[i][1]; 
     invoiceRow.ItemPrice = oTable[i][2]; 
     invoiceRow.RowTotal = oTable[i][3];   

     // adding to Invoice.InvoiceRow List Item 
     invoice.InvoiceRows.push(invoiceRow); 

     invoiceRow = { "RowDetail": "", "RowQty": "", "ItemPrice": "", "RowTotal": "" }; 
    } 
    // Step 1: Ends Here 


    // Set 2: Ajax Post 
    // Here i have used ajax post for saving/updating information 
    $.ajax({ 
     url: '/Invoice/Create', 
     data: JSON.stringify(invoice), 
     type: 'POST', 
     contentType: 'application/json;', 
     dataType: 'json', 
     success: function (result) 
     { 
      if (result.Success == "1") 
      { 
       window.location.href = "/Invoice/Index"; 
      } 
      else 
      { 
       alert(result.ex); 
      } 
     } 
    }); 
} 

</script> 
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script> 
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script> 
@using (Html.BeginForm()) 
{ 
@Html.ValidationSummary(true) 
<fieldset> 
    <legend>Invoice</legend> 

    @if (Model != null) 
    { 
     <input type="hidden" id="InvoiceID" name="InvoiceID" value="@Model.InvoiceID" /> 
    } 


    <div class="editor-label"> 
     @Html.LabelFor(model => model.ContractID, "Contract") 
    </div> 
    <div class="editor-field"> 
     @Html.DropDownList("ContractID", String.Empty) 
     @Html.ValidationMessageFor(model => model.ContractID) 
    </div> 
    <div class="editor-label"> 
     @Html.LabelFor(model => model.InvoiceDate) 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(model => model.InvoiceDate) 
     @Html.ValidationMessageFor(model => model.InvoiceDate) 
    </div> 
    <div class="editor-label"> 
     @Html.LabelFor(model => model.InvoiceNumber) 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(model => model.InvoiceNumber) 
     @Html.ValidationMessageFor(model => model.InvoiceNumber) 
    </div> 
    <div class="editor-label"> 
     @Html.LabelFor(model => model.PaymentDate) 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(model => model.PaymentDate) 
     @Html.ValidationMessageFor(model => model.PaymentDate) 
    </div> 
</fieldset> 

<br /> 

<fieldset> 
    <legend>Add Invoice Row</legend> 
    <br /> 
    <label> 
     Row Detail :</label> 
    @Html.TextBox("RowDetail") 
    <label> 
     Row Qty :</label> 
    @Html.TextBox("RowQty", null, new { style = "width:20px;text-align:center" }) 
    <label> 
     Item Price :</label> 
    @Html.TextBox("ItemPrice", null, new { style = "width:70px" }) 

    <input onclick="AddInvoiceItem()" type="button" value="Add Invoice Item" /> 
    <table id="tableItems" class="tableItems" width="400px"> 
     <thead> 
      <tr> 
       <th> 
        Detail 
       </th> 
       <th> 
        Qty 
       </th> 
       <th> 
        Price 
       </th> 
       <th> 
        Row Total 
       </th> 
      </tr> 
     </thead> 
     <tbody> 
      @if (Model != null) 
      { 
       foreach (var item in Model.InvoiceRows) 
       { 
       <tr> 
        <td> 
         @Html.DisplayFor(i => item.RowDetail) 
        </td> 
        <td> 
         @Html.DisplayFor(i => item.RowQty) 
        </td> 
        <td> 
         @Html.DisplayFor(i => item.ItemPrice) 
        </td> 
        <td> 
         @Html.DisplayFor(i => item.RowTotal) 
        </td> 
       </tr>      
       } 
      } 
     </tbody> 
    </table> 
    <br /> 
    <input onclick="DeleteRow()" type="button" value="Delete Selected Row" /> 
</fieldset>  

<p> 
    <input onclick="SaveInvoice()" type="submit" value="Save Invoice" /> 
</p> 

} 
<div> 
    @Html.ActionLink("Back to List", "Index") 
</div> 
+0

、それが失敗している正確にどのように無効なモデルエラーをダンプするために使用する拡張メソッドですか? –

+0

私はデータ型を使いこなし始め、すべての数値を整数に変更しています。関連するフィールドを小数点に戻し、物事が再び壊れ始めました。問題は、請求書の行です。単位(int)に単価(10進数)を掛け合わせると何とか何かが壊れてしまいます。請求書のAjaxポスティングはJQueryコードで正常に見えますが、結果は成功= 0が返されます。コントローラをチェックすると、請求書の行にnull値が表示されます。紛失してこの問題をデバッグする方法。 – Greg

+0

私が気づいたもう一つのことは、Ajaxの投稿がコントローラーに2回ぶつかっていることです。確かにAjaxは子供の行を含む請求書をポストしていますので、一度だけ投稿する必要があります。これは、unit * unitpriceで計算されるrowpriceに関係しますか?これはデータ型変換の問題のようです。 – Greg

答えて

0

あなたはモデルを調べて、エラーを抽出する必要があります。手元にあるものを使用することで、モデルバインダーが失敗する原因となっている問題を修正することができます。

は、ここで私は、出力コンソール

http://pastebin.com/S0gM3vqg

関連する問題