Best Practices for Inserting, Altering, and Deleting with EntityFramework

16

For deletion of records you may not have, but for Insertion and Amendment I believe there should already be something discussed.

The best recommended practice on Insertion and Change is ViewModel's , where you create a view that is appropriate for each case, then you will have the form data simple to do an Insertion, just passing the ViewModel data to the Domain .

I do not want to encourage or ask for advice on bad practices, but good details are always good, and yet there can be many simple cases of ViewModel's or cases where a Domain is simple for our case of a ViewModel

Well, an example:

Person :

public class Pessoa
{
    public int Id { get; set; }

    [StringLength(50)]
    [Required(AllowEmptyString = false)]
    public string Nome { get; set; }

    [Required]
    [DataType(DataType.Date)]
    [Column(TypeName = "Date")]
    public DateTime DataNascimento { get; set; }

    [InverseProperty("Pessoa")]
    public virtual ICollection<Telefone> Telefones { get; set; }
}

Phone :

public class Telefone
{
    public int Id { get; set; }

    [Required]
    public TipoTelefone TipoTelefone { get; set; }

    [StringLength(3)]
    [Required(AllowEmptyString = false)]
    public string Ddd { get; set; }

    [StringLength(10)]
    [Required(AllowEmptyString = false)]
    public string Numero { get; set; }
}

And then we have a View for people register that allows you to enter phone numbers, and with this we have some cases:

  • There may be numbers already registered (edit case);
  • You can enter new numbers (insert or edit case);
  • You can remove some numbers and even add others (editing cases).
  • Note: I believe I have listed them all.

    In editing cases it may even be simple, just leave the property Telefones of Pessoa fed and then add the database.

    But for insertion , a question: The Id of person will be passed directly to Telefones and then this simple insertion example registers Pessoa and Telefones ?

    [HttpPost]
    public ActionResult Save(Pessoa model)
    {
        if (ModelState.IsValid)
        {
            dbContext.Pessoas.Add(model);
            dbContext.SaveChanges();
        }
        return View(model);
    }
    

    To change: What is recommended to do to satisfy the possible conditions presented?

    [HttpPost]
    public ActionResult Edit(Pessoa model)
    {
        if (ModelState.IsValid)
        {
            var entry = dbContext.Pessoas.Find(model.Id);
            if (entry != null)
            {
                dbContext.Entry(Pessoa).CurrentValues.SetValues(model); // ???
                dbContext.SaveChanges();
    
                // E se:
                // 1. Existir números já cadastrados?
                // 2. Inserir novos números e outros já existiam?
                // 3. Alguns números e adicionar outros?
            }
            else
            {
                ModelState.AddModelError("", "Pessoa não encontrada!");
            }
        }
        return View(model);
    }
    

    What best practices in these scenarios, which I believe to be very general and explanatory in many cases?

    Detail : Same as example with ASP.NET MVC , it responds to other types and projects as well.

        
    asked by anonymous 26.10.2014 / 16:24

    1 answer

    9

    Introduction

    First of all, you need to understand how the DefaultModelBinder implementation works , which does not is mentioned in no response on the subject. It assumes that the variables on screen can be simple (primitive: int , float , String , bool ...) or complex (one object inside another, one collection inside another). It is this class that binds the IDs and field names of your form to the objects that are received by the Controller .

    Master-Detail, for DefaultModelBinder ", is an (master) object that has within it a Collection of objects of another type (or depending on the same master type). You, too, can implement your own ModelBinder , if you want, you can deploy your own DefaltModelBinder , if but I do not think it's necessary, because Jovem is great for most situations.

    An example on hand

    Let's do a manual implementation of a master-detail. Assume an object named Brinquedos and its collection of Jovem :

    public class Jovem
    {
        [Key]
        public int JovemId { get; set; }
    
        [Required]
        public String Nome { get; set; }
    
        pubic virtual ICollection<Brinquedo> Brinquedos { get; set; }
    }
    
    public class Brinquedo
    {
        [Key]
        public int BrinquedoId { get; set; }
        public int JovemId { get; set; }
    
        [Required]
        public String Nome { get; set; }
    
        public virtual Jovem Jovem { get; set; }
    }
    

    We want the same form to insert a Brinquedo and at least a Jovem into ModelBinder . So the form looks something like this:

      

    I'm using Bootstrap with Awesome Font to exemplify.

    @using SistemaDeJovens.Resources
    @model SistemaDeJovens.Models.Jovem
    
    @using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
    {
        @Html.AntiForgeryToken()
    
        <div class="form-horizontal">
            <h4>Cadastro de Jovem</h4>
            <hr />
            @Html.ValidationSummary(true, "", new { @class = "text-danger" })
            <div class="form-group">
                @Html.LabelFor(model => model.Nome, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.Nome, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
                </div>
            </div>
    
            <!-- Preste atenção nesse atributo -->
            <input type="hidden" name="Brinquedos.index" autocomplete="off" value="0">
    
            <div class="form-group">
                <label for="Brinquedos[0].Nome" class="control-label col-md-2" />
                <div class="col-md-10">
                    <input type="text" name="Brinquedos[0].Nome" id="Brinquedos_0__Nome" class="form-control ckeditor" />
                    <span class="field-validation-valid" data-valmsg-for="Brinquedos[0].Nome" data-valmsg-replace="true"></span>
                </div>
            </div>
    
            <div class="form-group">
                <div class="col-md-offset-2 col-md-10">
                    <input type="submit" value="Criar" class="btn btn-default" />
                </div>
            </div>
        </div>
    }
    
    <div>
        @Html.FontAwesomeActionLink("Voltar para Index", "Index", "fa-list", htmlAttributes: new { @class = "btn btn-default" })
    </div>
    

    Notice that I put everything fixed, plus an attribute called "index". Why does it exist? Steve Sanderson explains that% w / w% need it to know what is going to be associated with the detail object (note that this is nothing new, it's MVC2 thing). It does not have to be whole. In my projects, for example, "index" is always a Guid .

    And why did I set everything up? Because Html Helpers are unable to generate Html in the format of the indexes that are required for ModelBinder to correctly interpret your form.

    In the article already quoted, Steve Sanderson also explains the difficulty of doing this at hand, and that's why the NuGet package was created that I urge you both to use: BeginCollectionItem .

    BeginCollectionItemHelper Examples

    I have already addressed the subject in these answers:

    Questions

    The person ID will be passed directly to Telephones and then this simple example of insertion registers the Person and the Telephones?

    In the case of the insertion, if you have a Model Pessoa not yet saved with a Collection Telefones , in the case of Entity Framework 6, object Pessoa will be saved before, it will get an Id, and soon after each Telefone will be inserted. No assignments needed.

    In the case of Entity Framework 5, it may still be necessary to assign some more information to Telefone objects because the framework was still not very smart to read and save aggregate objects as Entity Framework 6 does.

    What is recommended to do then to satisfy the possible conditions presented?

  • Are there numbers already registered?

    If the number is being registered in repetition, you can fetch the phones first (using AsNoTracking() to avoid context monitoring) and iterate the list that comes from the form with the list that came from the database.

  • Insert new numbers and others already exist?

    Just enter the new numbers. The answers already mentioned give examples of how to do this.

  • Some numbers and add others?

    I believe it's one of the two cases above.

  • What best practices do these scenarios, which I believe are very general and explanatory in many cases?

    There is not much secret: the checks are usually in the edit of the parent record, and never in the insert. What you can look at in the insert are duplicate numbers, invalid numbers, etc.

        
    26.10.2014 / 17:58