wake-up-neo.net

Speichern von Daten zwischen Anforderungen in dbcontext

Ich habe eine Seite mit serverseitiger Wiedergabe mit Rasiermesser, auf der Sie einige Elemente aus verschiedenen Listen hinzufügen, einige Felder ausfüllen und beim Senden eine Anfrage erstellen können. 

Jedes Mal, wenn ein Element aus einer Liste hinzugefügt/entnommen wird, sende ich einen Beitrag mit der Schaltfläche "Senden" an eine bestimmte Aktion, z. "CustomerSelected". Ich mache das, weil ich zusätzliche Ansichtskomponenten für das hinzugefügte Element neu erstellen muss. In diesen Methoden möchte ich dem db-Kontext zusätzliche Objekte hinzufügen. Daher kann ich beim Senden einfach SaveChanges() sagen und muss nicht alles in derselben Methode zusammenstellen. Im .net-Kerndatenbankkontext erfolgt jedoch jede Anforderung, und es ist ratsam, dies so zu halten. In diesem Fall, wie kann ich diese temporären Entitätsobjekte zwischen Anforderungen speichern. Wenn sich jemand entscheidet, sie einzureichen, kann ich später sagen, SaveChanges() oder anderweitig verwerfen.

Ich hätte gerne so etwas:

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

Wenn dies nicht möglich ist, habe ich darüber nachgedacht, einzelne Elemente in jede Methode einzufügen und sie dort zu speichern, und dann würde ich das letzte letzte Element erstellen. Wenn jedoch jemand seinen Browser schließt, ohne ihn zu senden, habe ich unvollständige Daten in meiner Datenbank. Ich müsste einen Job ausführen, um diese zu löschen, und es scheint zu viel für eine so einfache Aufgabe zu sein.

7
FCin

Es ist keine gute Idee, Serverressourcen zu verwenden, um Änderungen in solchen Szenarien nachzuverfolgen. In Szenarien wie Einkaufskorb, Liste oder Stapelbearbeitung ist es besser, Änderungen auf Kundenseite zu verfolgen. 

Ihre Anforderung für das Generieren von Ansichten auf Serverseite bedeutet nicht, dass Sie Änderungen in DbContext verfolgen müssen. Rufen Sie die Indexansicht ab und erstellen Sie eine Ansicht vom Server, verfolgen Sie jedoch die Änderungen auf dem Client. Buchen Sie dann zum Speichern alle Daten auf dem Server, um die Änderungen basierend auf Ihren Tracking-Informationen zu speichern.

Der Mechanismus für die clientseitige Änderungsverfolgung hängt von der Anforderung und dem Szenario ab. Sie können beispielsweise Änderungen mithilfe von HTML-Eingaben nachverfolgen, Änderungen mithilfe von Cookies nachverfolgen und Änderungen mithilfe von Javascript-Objekten im Browserspeicher verfolgen, beispielsweise in Winkelszenarien.

Hier ist dieser Beitrag Ich werde ein Beispiel mit HTML-Eingaben und Modellbindung zeigen. Um mehr über dieses Thema zu erfahren, werfen Sie einen Blick auf diesen Artikel von Phill Haack: Modellbindung an eine Liste .

Beispiel

Im folgenden Beispiel beschreibe ich ein Listenbearbeitungsszenario für eine Kundenliste. Um es einfach zu machen, nehme ich an:

  • Sie haben eine Liste von Kunden, die Sie beim Kunden bearbeiten möchten. Sie möchten möglicherweise Elemente hinzufügen, bearbeiten oder löschen.
  • Beim Hinzufügen eines neuen Elements sollte die Zeilenvorlage für die neue Zeile vom Server stammen.
  • Beim Löschen markieren Sie ein Element als gelöscht, indem Sie auf ein Kontrollkästchen in der Zeile klicken.
  • Beim Hinzufügen/Bearbeiten möchten Sie Validierungsfehler in der Nähe der Zellen anzeigen.
  • Sie möchten die Änderungen am Ende speichern, indem Sie auf die Schaltfläche Speichern klicken.

Um das obige Szenario zu implementieren, müssen Sie folgende Modelle, Aktionen und Ansichten erstellen:

Trackable <T> -Modell

Diese Klasse ist ein Modell, das uns bei der clientseitigen Verfolgung und Listenbearbeitung hilft:

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

Kundenmodell

Das Kundenmodell:

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

Die Indexansicht ist für das Rendern von List<Trackable<Customer>> verantwortlich. Beim Rendern jedes Datensatzes verwenden wir RowTemplate view. Dieselbe Ansicht, die wir beim Hinzufügen neuer Artikel verwenden.

In dieser Ansicht haben wir eine Schaltfläche zum Speichern zum Speichern und eine Schaltfläche zum Hinzufügen neuer Zeilen, die die Aktion Aktion mit ajax aufrufen.

Hier ist die Indexansicht:

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

Diese Ansicht ist für das Rendern eines Kundendatensatzes verantwortlich. In dieser Ansicht rendern wir zuerst die Variable Index in einem verborgenen Bereich, setzen dann ein Präfix [index] für die Felder und rendern dann die Felder, einschließlich Index, hinzugefügt, gelöscht und Modell-ID:

Hier ist die RowTemplate-Ansicht:

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

Es wird die folgenden Aktionen haben.

[GET]-Indexaktion

In dieser Aktion können Sie Daten aus der Datenbank laden und zu einem List<Trackable<Customer>> formen und an die Index-Ansicht übergeben:

[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] Aktion erstellen

Diese Aktion ist dafür verantwortlich, eine neue Zeilenvorlage zurückzugeben. Es wird von einer Schaltfläche in der Indexansicht mit ajax aufgerufen:

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

[POST] Indexaktion

Diese Aktion ist dafür verantwortlich, dass das verfolgte Element vom Client empfangen und gespeichert wird. Das Modell, das es erhält, ist List<Trackable<Customer>>. Zuerst werden die Überprüfungsfehlermeldungen für gelöschte Zeilen entfernt. Entfernt dann diejenigen, die gelöscht und hinzugefügt werden. Überprüft dann, ob der Modellstatus gültig ist, und versucht, Änderungen an der Datenquelle vorzunehmen.

Elemente mit der Eigenschaft Deleted als true werden gelöscht, Elemente mit Added als true und Deleted als false sind neue Elemente, und die restlichen Elemente werden bearbeitet. Dann müssen Sie, ohne alle Elemente aus der Datenbank laden zu müssen, einfach mit einer for-Schleife db.Entry für jedes Element aufrufen, deren Status festlegen und die Änderungen speichern.

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

Wie wäre es mit dynamischen Formularen mit Javascript und Verwenden von type="hidden" oder visibility Und Senden dann alles auf einmal

Oder verwenden Sie TempData mit Weiterleitungen und verwenden Sie diese Daten in anderen Ansichten (Formular) als input type="hidden".

Fließen:

Form1 -> 

Controller-Methode speichert Daten in TempData und leitet Umleitungen in Form2-Ansicht/oder -Datenansicht um und gibt Form2-Ansicht zurück. ->

Bei Form2 wurde TempData unter ausgeblendete Eingaben in das Formular eingefügt -> 

Beides auf einmal einreichen

0
Joelty