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>
、それが失敗している正確にどのように無効なモデルエラーをダンプするために使用する拡張メソッドですか? –
私はデータ型を使いこなし始め、すべての数値を整数に変更しています。関連するフィールドを小数点に戻し、物事が再び壊れ始めました。問題は、請求書の行です。単位(int)に単価(10進数)を掛け合わせると何とか何かが壊れてしまいます。請求書のAjaxポスティングはJQueryコードで正常に見えますが、結果は成功= 0が返されます。コントローラをチェックすると、請求書の行にnull値が表示されます。紛失してこの問題をデバッグする方法。 – Greg
私が気づいたもう一つのことは、Ajaxの投稿がコントローラーに2回ぶつかっていることです。確かにAjaxは子供の行を含む請求書をポストしていますので、一度だけ投稿する必要があります。これは、unit * unitpriceで計算されるrowpriceに関係しますか?これはデータ型変換の問題のようです。 – Greg