代码之家  ›  专栏  ›  技术社区  ›  FCin

在dbcontext中存储请求之间的数据

  •  7
  • FCin  · 技术社区  · 6 年前

    我有一个使用Ra剃刀的服务器端渲染页面,在那里你可以从不同的列表中添加一些元素,填充一些字段并在提交上创建一个请求。

    每次从任何列表中添加/获取项目时,我都会向特定操作发送一个带有“提交”按钮的帖子,例如“customerselected”。我这样做是因为我需要为添加的项重新创建其他视图组件。在这些方法中,我想在DB上下文中添加添加的对象,所以在提交时,我可以说 SaveChanges() 也不必用同样的方法组装所有的东西。但在.NET Core DB中,上下文是每个请求的上下文,建议保持这种方式。在这种情况下,如何在请求之间存储这些临时实体对象,以便以后有人决定提交它们时,我可以说 保存更改() 或者丢弃它们?

    我想要这样的东西:

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

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

    3 回复  |  直到 6 年前
        1
  •  3
  •   Reza Aghaei    6 年前

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

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

    客户端更改跟踪的机制取决于需求和场景,例如,您可以使用HTML输入跟踪更改,您可以使用Cookie跟踪更改,您可以像JavaScript对象那样在浏览器内存中跟踪更改,如角度场景。

    这是本文,我将展示一个使用html输入和模型绑定的示例。要了解有关此主题的更多信息,请参阅Phill Haack的这篇文章: Model Binding To A List .

    例子

    在下面的示例中,我描述了客户列表的列表编辑场景。简单来说,我想:

    • 你有一份客户名单,你要在客户那里编辑。您可能需要添加、编辑或删除项目。
    • 添加新项时,新行的行模板应来自服务器。
    • 删除时,通过单击行上的复选框将项目标记为已删除。
    • 添加/编辑时,希望在单元格附近显示验证错误。
    • 要在结尾保存更改,请单击“保存”按钮。

    要实现上述场景,您需要创建以下模型、操作和视图:

    可跟踪<t>模型

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

    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调用create操作。

    以下是索引视图:

    @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>
    

    客户控制器

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

    它将具有以下操作。

    [获取]索引操作

    在此操作中,可以从数据库加载数据并将其赋形为 列表<可跟踪<客户>> 然后传给 索引 观点:

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

    [获取]创建操作

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

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

    [发布]索引操作

    此操作负责从客户端接收跟踪项并保存它们。它收到的模型是 列表<可跟踪<客户>> . 它首先删除已删除行的验证错误消息。然后删除那些既被删除又被添加的内容。然后检查模型状态是否有效,尝试对数据源应用更改。

    项目有 Deleted 属性为true时,将删除具有 Added 为真 删除 由于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");
    }
    
        2
  •  0
  •   Joelty    6 年前

    使用javascript和 type="hidden" visibility 然后立刻把所有的东西

    或者对重定向使用tempdata并在其他视图(表单)中重用该数据 input type="hidden"

    Flow:

    形式1-GT;

    控制器的方法将数据保存在tempdata中,并重定向到form2视图/或view data并返回form2视图?-gt;

    窗体2已在“隐藏输入”下将tempdata插入到窗体中->

    同时提交两者

        3
  •  -1
  •   Mohamed Elrashid    6 年前

    饼干!

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

    示例链接

    enter image description here enter image description here enter image description here enter image description here