在dbcontext中的请求之间存储数据 [英] Storing data between requests in dbcontext

查看:75
本文介绍了在dbcontext中的请求之间存储数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个页面使用剃刀进行服务器端渲染,您可以在其中添加来自不同列表的几个元素,填充一些字段并在提交时从中创建请求.

I have a page with server side rendering using razor, where you can add a couple of elements from different lists, fill some fields and create a request from it on submit.

每次添加/从任何列表中提取某项时,我都会向带有特定按钮的操作发送带有提交"按钮的帖子,例如客户已选择".我这样做是因为我需要为添加的项目重新创建其他视图组件.在这些方法中,我想将添加的对象添加到db上下文中,因此在提交时,我只能说SaveChanges(),而不必在同一方法中组装所有内容.但是在.net核心db上下文中,每个请求都是这样,建议保持这种方式.在这种情况下,我如何在请求之间存储这些临时实体对象,以便以后如果有人决定提交它们,我可以说SaveChanges()或否则丢弃它们?

Each time an item is added/taken from any list, I send a post with submit button to a specific action, e.g. "CustomerSelected". I do this, because I need to recreate additional view components for the added item. In these methods I would like to add added objects to the db context, so on submit I can just say SaveChanges() and not have to assemble everything in the same method. But in .net core db context is per request and it is advisable to keep it that way. In this case how can I store these temporary entity objects between requests so later if someone decides to submit them I can say SaveChanges() or discard them otherwise?

我想要这样的东西:

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();
}

如果这不可能,那么我正在考虑在每种方法中添加单个元素,然后将它们保存在那里,然后提交,我将构建最后一个最终元素.但是,如果有人关闭了浏览器却没有提交,那么我的数据库中的数据将不完整.我将不得不执行某种工作来删除这些作业,而对于这样一个简单的任务来说似乎太多了.

If this is not possible then I was thinking about adding individual elements in each method and save them there and onsubmit I would build the last final element. But if someone closes their browser without submitting then I have incomplete data laying in my database. I would have to run some kind of job to delete those and it seems to be too much for such a simple task.

推荐答案

在这种情况下,使用服务器资源来跟踪更改不是一个好主意.在购物篮,列表或批处理编辑等场景中,最好在客户端跟踪更改.

It's not good idea to use server resources to track changes in such scenarios. In scenarios like shopping basket, list or batch editing it's better track changes at client-side.

您需要在服务器端生成视图,但这并不意味着您需要跟踪DbContext中的更改.从服务器获取索引视图并创建视图,但是跟踪客户端上的更改.然后保存,将所有数据发布到服务器,以根据您拥有的跟踪信息保存更改.

Your requirement to get Views generated at server-side doesn't mean you need to track changes in DbContext. Get the index view and create view from server, but track changes on client. Then to save, post all data to the server to save changes based on the tracking info that you have.

客户端更改跟踪的机制取决于需求和方案,例如,您可以使用html输入来跟踪更改,可以使用cookie来跟踪更改,可以使用浏览器内存中的javascript对象(如角度方案)来跟踪更改.

The mechanism for client-side change tracking depends to the requirement and the scenario, for example you can track changes using html inputs, you can track changes using cookie, you can track changes using javascript objects in browser memory like angular scenarios.

这里是这篇文章,我将展示一个使用html输入和模型绑定的示例.要了解有关此主题的更多信息,请查看Phill Haack的这篇文章:

Here is this post I'll show an example using html inputs and model binding. To learn more about this topic, take a look at this article by Phill Haack: Model Binding To A List.

在下面的示例中,我描述了一个针对客户列表的列表编辑方案.为了简单起见,我想:

In the following example I describe a list editing scenario for a list of customers. To make it simple, I suppose:

  • 您有要在客户端编辑的客户列表.您可能要添加,编辑或删除项目.
  • 添加新项目时,新行的行模板应来自服务器.
  • 删除时,通过单击该行上的复选框,将项目标记为已删除.
  • 添加/编辑时,您想在单元格附近显示验证错误.
  • 您要在最后保存更改,方法是单击保存"按钮.

要实现上述方案,那么您需要创建以下模型,操作和视图:

To implement above scenario Then you need to create following models, actions and views:

可跟踪的< T>型号

Trackable<T> Model

此类是一个可帮助我们进行客户端跟踪和列表编辑的模型:

This class is a model which helps us in client side tracking and list editing:

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; }
}

客户模型

Customer Model

客户模型:

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视图

Index.cshtml View

索引视图负责呈现List<Trackable<Customer>>.呈现每个记录时,我们使用RowTemplate视图.添加新项目时使用的视图相同.

The Index view is responsible to render List<Trackable<Customer>>. When rendering each record, we use RowTemplate view. The same view which we use when adding new item.

在此视图中,我们具有一个用于保存的提交按钮和一个用于添加新行的按钮,这些按钮调用使用ajax的创建操作.

In this view, we have a submit button for save and a button for adding new rows which calls Create action using 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视图

RowTemplate.cshtml View

此视图负责呈现客户记录.在此视图中,我们首先在隐藏状态下渲染Index,然后为字段设置前缀[index],然后渲染字段,包括再次索引,添加,删除和模型ID:

This view is responsible to render a customer record. In this view, we first render the Index in a hidden, then set a prefix [index] for the fields and then render the fields, including index again, added, deleted and model id:

这是RowTemplate视图:

Here is RowTemplate View:

@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

CustomerController

public class CustomerController : Controller
{
    private static List<Customer> list;
}

它将执行以下操作.

[GET]索引操作

[GET] Index Action

在此操作中,您可以从数据库加载数据并将其整形为List<Trackable<Customer>>并传递到Index视图:

In this action you can load data from database and shape it to a List<Trackable<Customer>> and pass to the Index View:

[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]创建操作

[GET] Create Action

此操作负责返回新的行模板.将使用ajax通过索引视图中的按钮调用它:

This action is responsible to returning new row template. It will be called by a button in Index View using ajax:

[HttpGet]
public IActionResult Create()
{
    var model = new Trackable<Customer>(new Customer()) { Added = true };
    return PartialView("RowTemplate", model);
}

[POST]索引操作

[POST] Index Action

此操作负责从客户端接收跟踪的项目并保存它们.它收到的模型为List<Trackable<Customer>>.首先,它会删除已删除行的验证错误消息.然后删除同时删除和添加的那些.然后检查模型状态是否有效,尝试将更改应用于数据源.

This action is responsible for receiving the tracked item from client and save them. The model which it receives is List<Trackable<Customer>>. It first strips the validation error messages for deleted rows. Then removes those which are both deleted and added. Then checks if model state is valid, tries to apply changes on data source.

具有Deleted属性为true的项目被删除,具有Added为true和Deleted为false的项目是新项目,其余项目被编辑.然后,无需使用数据库就可以加载所有项目,只需使用for循环,为每个项目调用db.Entry并设置它们的状态,最后保存更改即可.

Items having Deleted property as true are deleted, items having Added as true and Deleted as false are new items, and rest of items are edited. Then without needing to load all items from database, just using a for loop, call db.Entry for each item and set their states and finally save changes.

[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");
}

这篇关于在dbcontext中的请求之间存储数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆