我有一个使用剃刀渲染服务器端的页面,您可以在其中添加来自不同列表的几个元素,填充一些字段并在提交时从中创建请求。
每次从任何列表中添加/获取一个项目时,我都会通过“提交”按钮向特定操作发送一条帖子,例如“客户已选择”。我这样做是因为我需要为添加的项目重新创建其他视图组件。在这些方法中,我想将添加的对象添加到db上下文中,因此在提交时,我只能说SaveChanges()
,而不必在同一方法中组装所有内容。但是在.net核心db上下文中,每个请求都是这样,建议保持这种方式。在这种情况下,我如何在请求之间存储这些临时实体对象,以便以后如果有人决定提交它们,我可以说SaveChanges()
,否则可以丢弃它们?
我想要这样的东西:
public IActionResult CustomerAdded(int customerId)
{
var customer = _context.Customers.First(c => c.IdCustomer == customerId);
var message = _context.Messages.First(m => m.IdMessage = _idMessage);
message.Customers.Add(customer);
return View();
}
public IActionResult ItemAdded(int itemId)
{
var item = _context.Items.First(c => c.IdItem == itemId);
var message = _context.Messages.First(m => m.IdMessage = _idMessage);
message.Items.Add(item);
return View();
}
public IActionResult Submit()
{
_context.SaveChanges();
return View();
}
如果这不可能,那么我正在考虑在每种方法中添加单个元素并将其保存在那里,并在提交时我将构建最后一个最终元素。但是,如果有人不提交就关闭浏览器,那么我的数据库中的数据将不完整。我必须执行某种工作才能删除这些作业,对于这样一个简单的任务来说似乎太多了。
答案 0 :(得分:3)
在这种情况下使用服务器资源跟踪更改不是一个好主意。在购物篮,列表或批处理编辑等场景中,最好在客户端跟踪更改。
您需要在服务器端生成视图并不意味着您需要跟踪DbContext
中的更改。从服务器获取索引视图并创建视图,但是跟踪客户端上的更改。然后保存,将所有数据发布到服务器以根据您的跟踪信息保存更改。
客户端更改跟踪的机制取决于需求和方案,例如,您可以使用html输入来跟踪更改,可以使用cookie来跟踪更改,可以使用浏览器内存中的javascript对象(如角度方案)来跟踪更改。
这是本文,我将展示一个使用html输入和模型绑定的示例。要了解有关此主题的更多信息,请查看Phill Haack的这篇文章:Model Binding To A List。
在下面的示例中,我描述了针对客户列表的列表编辑方案。为了简单起见,我想:
要实现上述方案,那么您需要创建以下模型,操作和视图:
可跟踪
此类是一个可帮助我们进行客户端跟踪和列表编辑的模型:
public class Trackable<T>
{
public Trackable() { }
public Trackable(T model) { Model = model; }
public Guid Index { get; set; } = Guid.NewGuid();
public bool Deleted { get; set; }
public bool Added { get; set; }
public T Model { get; set; }
}
客户模型
客户模型:
public class Customer
{
[Display(Name ="Id")]
public int Id { get; set; }
[StringLength(20, MinimumLength = 1)]
[Required]
[Display(Name ="First Name")]
public string FirstName { get; set; }
[StringLength(20, MinimumLength = 1)]
[Required]
[Display(Name ="Last Name")]
public string LastName { get; set; }
[EmailAddress]
[Required]
[Display(Name ="Email Name")]
public string Email { get; set; }
}
Index.cshtml视图
索引视图负责呈现List<Trackable<Customer>>
。呈现每条记录时,我们使用RowTemplate
视图。添加新项目时使用的视图相同。
在此视图中,我们具有一个用于保存的提交按钮和一个用于添加新行的按钮,这些按钮调用使用ajax的创建操作。
这是索引视图:
@model IEnumerable<Trackable<Customer>>
<h2>Index</h2>
<form method="post" action="Index">
<p>
<button id="create">New Customer</button>
<input type="submit" value="Save All">
</p>
<table class="table" id="data">
<thead>
<tr>
<th>
Delete
</th>
<th>
@Html.DisplayNameFor(x => x.Model.FirstName)
</th>
<th>
@Html.DisplayNameFor(x => x.Model.LastName)
</th>
<th>
@Html.DisplayNameFor(x => x.Model.Email)
</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
await Html.RenderPartialAsync("RowTemplate", item);
}
</tbody>
</table>
</form>
@section Scripts{
<script>
$(function () {
$('#create').click(function (e) {
e.preventDefault();
$.ajax({
url: 'Create',
method: 'Get',
success: function (data) {
$('#data tbody tr:last-child').after(data);
},
error: function (e) { alert(e); }
});
});
});
</script>
}
RowTemplate.cshtml视图
此视图负责呈现客户记录。在此视图中,我们首先在隐藏状态下渲染Index
,然后为字段设置前缀[index]
,然后渲染字段,包括再次索引,添加,删除和模型ID:
这是RowTemplate视图:
@model Trackable<Customer>
<tr>
<td>
@Html.HiddenFor(x => x.Index)
@{Html.ViewData.TemplateInfo.HtmlFieldPrefix = $"[{Model.Index}]";}
@Html.HiddenFor(x => x.Index)
@Html.HiddenFor(x => x.Model.Id)
@Html.HiddenFor(x => x.Added)
@Html.CheckBoxFor(x => x.Deleted)
</td>
<td>
@Html.EditorFor(x => x.Model.FirstName)
@Html.ValidationMessageFor(x => x.Model.FirstName)
</td>
<td>
@Html.EditorFor(x => x.Model.LastName)
@Html.ValidationMessageFor(x => x.Model.LastName)
</td>
<td>
@Html.EditorFor(x => x.Model.Email)
@Html.ValidationMessageFor(x => x.Model.Email)
</td>
</tr>
CustomerController
public class CustomerController : Controller
{
private static List<Customer> list;
}
它将执行以下操作。
[GET]索引操作
在此操作中,您可以从数据库加载数据并将其整形为List<Trackable<Customer>>
并传递到Index
视图:
[HttpGet]
public IActionResult Index()
{
if (list == null)
{
list = Enumerable.Range(1, 5).Select(x => new Customer()
{
Id = x,
FirstName = $"A{x}",
LastName = $"B{x}",
Email = $"A{x}@B{x}.com"
}).ToList();
}
var model = list.Select(x => new Trackable<Customer>(x)).ToList();
return View(model);
}
[GET]创建操作
此操作负责返回新的行模板。将使用ajax通过索引视图中的按钮调用它:
[HttpGet]
public IActionResult Create()
{
var model = new Trackable<Customer>(new Customer()) { Added = true };
return PartialView("RowTemplate", model);
}
[POST]索引操作
此操作负责从客户端接收跟踪的项目并保存它们。它收到的模型是List<Trackable<Customer>>
。首先,它会删除已删除行的验证错误消息。然后删除同时删除和添加的那些。然后检查模型状态是否有效,尝试将更改应用于数据源。
具有Deleted
属性为true的项目被删除,具有Added
为true和Deleted
为false的项目是新项目,其余项目被编辑。然后,无需使用数据库就可以加载所有项目,只需使用for循环,为每个项目调用db.Entry
并设置它们的状态,最后保存更改即可。
[HttpPost]
public IActionResult Index(List<Trackable<Customer>> model)
{
//Cleanup model errors for deleted rows
var deletedIndexes = model.
Where(x => x.Deleted).Select(x => $"[{x.Index}]");
var modelStateDeletedKeys = ModelState.Keys.
Where(x => deletedIndexes.Any(d => x.StartsWith(d)));
modelStateDeletedKeys.ToList().ForEach(x => ModelState.Remove(x));
//Removing rows which are added and deleted
model.RemoveAll(x => x.Deleted && x.Added);
//If model state is not valid, return view
if (!ModelState.IsValid)
return View(model);
//Deleted rows
model.Where(x => x.Deleted && !x.Added).ToList().ForEach(x =>
{
var i = list.FindIndex(c => c.Id == x.Model.Id);
if (i >= 0)
list.RemoveAt(i);
});
//Added rows
model.Where(x => !x.Deleted && x.Added).ToList().ForEach(x =>
{
list.Add(x.Model);
});
//Edited rows
model.Where(x => !x.Deleted && !x.Added).ToList().ForEach(x =>
{
var i = list.FindIndex(c => c.Id == x.Model.Id);
if (i >= 0)
list[i] = x.Model;
});
//Reditect to action index
return RedirectToAction("Index");
}
答案 1 :(得分:0)
使用javascript并使用type="hidden"
或visibility
的动态表单怎么样?
然后一次发送所有内容
或者将TempData与重定向一起使用,并以input type="hidden"
的形式在其他视图(窗体)中重复使用该数据
流量:
Form1->
控制器的方法将数据保存在TempData中并重定向到Form2 View /或ViewData并返回Form2 View? ->
Form2将TempData插入到隐藏输入下的表单中->
一次提交两个
答案 2 :(得分:-1)
Cookie!
public class HomeController : Controller
{
public string Index()
{
HttpCookie cookie = Request.Cookies["message"];
Message message = null;
string json = "";
if (cookie == null)
{
message = new Message();
json = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(message);
cookie = new HttpCookie("message", json);
}
Response.Cookies.Add(cookie);
return json;
}
public string CustomerAdded(int id)
{
HttpCookie cookie = Request.Cookies["message"];
Message message = null;
string json = "";
if (cookie == null || string.IsNullOrEmpty(cookie.Value))
{
message = new Message();
json = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(message);
cookie = new HttpCookie("message", json);
}
else
{
json = cookie.Value;
message = new System.Web.Script.Serialization.JavaScriptSerializer().Deserialize<Message>(json);
}
if (message.Customers == null) message.Customers = new List<int>();
if (message.Items == null) message.Items = new List<int>();
if (!message.Customers.Contains(id))
{
message.Customers.Add(id);
}
json = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(message);
cookie = new HttpCookie("message", json);
Response.Cookies.Add(cookie);
return json;
}
public string ItemAdded(int id)
{
HttpCookie cookie = Request.Cookies["message"];
Message message = null;
string json = "";
if (cookie == null || string.IsNullOrEmpty(cookie.Value))
{
message = new Message();
json = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(message);
cookie = new HttpCookie("message", json);
}
else
{
json = cookie.Value;
message = new System.Web.Script.Serialization.JavaScriptSerializer().Deserialize<Message>(json);
}
if (message.Customers == null) message.Customers = new List<int>();
if (message.Items == null) message.Items = new List<int>();
if (!message.Items.Contains(id))
{
message.Items.Add(id);
}
json = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(message);
cookie = new HttpCookie("message", json);
Response.Cookies.Add(cookie);
return json;
}
public string Submit()
{
HttpCookie cookie = Request.Cookies["message"];
Message message = null;
string json = "";
if (cookie == null || string.IsNullOrEmpty(cookie.Value))
{
return "no data";
}
else
{
json = cookie.Value;
message = new System.Web.Script.Serialization.JavaScriptSerializer().Deserialize<Message>(json);
}
Response.Cookies["message"].Value = "";
Response.Cookies["message"].Expires = DateTime.Now.AddDays(-1);
return "Submited";
}
}