How and where to implement business rules in the Entity Framework?

Asked

Viewed 342 times

4

I have the following example of a software that uses Entity Framework, accessing a database with only one table called Produtos with the following fields:

  • Field int produtoid.
  • Field string nomeproduto.
  • Field int categoriaid.

It also has a form where I perform the CRUD, see:

formulario

Here follows the code of the two files generated by EF which is mine Context and my class Produtos.

Class Produtos:

namespace CRUD_EF
{
    using System;
    using System.Collections.Generic;
    
    public partial class Produtos
    {
        public int produtoid { get; set; }
        public string nomeproduto { get; set; }
        public int categoriaid { get; set; }
    }
}

Class ExemploEFEntities:

namespace CRUD_EF
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    
    public partial class ExemploEFEntities : DbContext
    {
        public ExemploEFEntities()
            : base("name=ExemploEFEntities")
        {
        }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }
    
        public virtual DbSet<Produtos> Produtos { get; set; }
    }
}

And this is the entire code of my form (Form1.Cs):

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CRUD_EF
{
    public partial class frmPrincipal : Form
    {
        public frmPrincipal()
        {
            InitializeComponent();
        }

        private void frmPrincipal_Load(object sender, EventArgs e)
        {
            lerProdutos();
        }

        private void lerProdutos() 
        {
            ExemploEFEntities context = new ExemploEFEntities();

            IEnumerable<Produtos> produtos = from p 
                                             in context.Produtos 
                                             select p;

            dataGridViewProdutos.DataSource = produtos.ToList();
        }

        private void incluir(string nomeProduto, int idCategoria) 
        {
            ExemploEFEntities context = new ExemploEFEntities();
            
            Produtos novoProduto = new Produtos()
            {
                nomeproduto = nomeProduto,
                categoriaid = idCategoria
            };

            context.Produtos.Add(novoProduto);
            context.SaveChanges();

            lerProdutos();
        }

        private void btnIncluir_Click(object sender, EventArgs e)
        {
            incluir(txtNome.Text, Convert.ToInt32(txtCategoriaID.Text));
        }

        private void btnAlterar_Click(object sender, EventArgs e)
        {
            alterar();
        }

        private void alterar() 
        {
            ExemploEFEntities context = new ExemploEFEntities();

            int id = Convert.ToInt32(txtProdutoId.Text);

            Produtos produto = context.Produtos.First(p => p.produtoid == id);
            produto.nomeproduto = txtNome.Text;
            produto.categoriaid = Convert.ToInt32(txtCategoriaID.Text);                        

            context.SaveChanges();

            lerProdutos();
        }

        private void deletar() 
        {
            ExemploEFEntities context = new ExemploEFEntities();
            
            int id = Convert.ToInt32(txtProdutoId.Text);

            Produtos produto = context.Produtos.First(p => p.produtoid == id);

            context.Produtos.Remove(produto);
            context.SaveChanges();

            lerProdutos();
        }

        private void btnExcluir_Click(object sender, EventArgs e)
        {
            deletar();
        }

        private void query(int id) 
        {
            ExemploEFEntities context = new ExemploEFEntities();

            Produtos produto = context.Produtos.First(p => p.produtoid == id);

            txtProdutoId.Text = produto.produtoid.ToString();
            txtNome.Text = produto.nomeproduto.ToString();
            txtCategoriaID.Text = produto.categoriaid.ToString();
        }

        private void dataGridViewProdutos_CellEnter(object sender, DataGridViewCellEventArgs e)
        {
            try 
            {
                int id = Convert.ToInt32(dataGridViewProdutos.Rows[e.RowIndex].Cells[0].Value);
                
                query(id);
            }
            catch 
            {
                MessageBox.Show("Houve um erro!");
            }
        }
    }
}

My doubt.

Taking into account all the above structure generated by Entity Framework i would like to know how and where I could implement the business rules?

To facilitate and illustrate the situation we will consider the following rule:

Registering products with the exact same name is not allowed.

How and where I would implement this rule?

  • 1

    drmcarvalho, beware of declaring your context outside a block using, this will generate a waste of resources, so always do as in the @Smael examples.

  • 1

    As for adding restrictions, you don’t need to use Repository Patterns , just make use of Data Annotations and/or rules in Mapeamento, things like record size, single sets of records, restructures (single value, range, larger than other field, etc.), relationships are easily configured using DataAnnotations or in the Mapping.

  • Yes, how could I use the Annotations? You could publish a reply?

3 answers

6


Your question is a bit complex in terms of implementation. Business rules are not an easy subject to discuss. There is this question where is explained a little about this.

But, trying to answer a little, you can do it in a few ways. I advise two ways. One is using the Dataannotations, like the @Tobymosque comments and the other way will be using the IValidableObject.

I do not advise creating a method just for this, because the framework and the language you are using offer better alternatives.

Using Dataannotations, you would need to create a new attribute. This answer has an example of how to implement.

If you want to use IValidableObject, can you see an example in this question.

  • 2

    Looking at the technology used in the question, the @Smael’s answer is interesting, but I wouldn’t advise using the bank for that. You have many ways to do this without creating triggers in the bank.

  • 1

    If I put all the forms and examples here, the answer would be too long, and I think you wouldn’t be able to understand the concepts very well. If you want more information, ask questions about the questions, which will be better.

4

For example, before entering or changing your record, you could call a method (boolean) with the necessary rules.

The rules could be defined in the database itself through triggers or even stored procedures that would be called by the application (there are several pros in this type of implementation).

Focusing only on the proposed problem, see an example below:

private void incluir(string nomeProduto, int idCategoria) 
{
    if (RegistroValido(nomeProduto, idCategoria))
    {
        using (ExemploEFEntities context = new ExemploEFEntities())
        {
            Produtos novoProduto = new Produtos()
            {
                nomeproduto = nomeProduto,
                categoriaid = idCategoria
            };

            context.Produtos.Add(novoProduto);
            context.SaveChanges();
        }

        lerProdutos();
    }
}


private bool RegistroValido(string nomeProduto, int idCategoria)
{
    bool retValido = false;
    int erro = 0;
    using (ExemploEFEntities context = new ExemploEFEntities())
    {
        //busca na tabela de produtos um com o mesmo nome
        if (context.Produtos.Count(x => x.nomeproduto.ToUpper().Equals(nomeProduto.ToUpper())) > 0)
            erro = 1;

        if (idCategoria == 0)
            erro = 2;
    }

    swicth (erro)
    {
        case 1:
            MessageBox.Show("Não é permitido cadastrar produtos com o nome exatamente igual.","Atenção!");
            break;
        case 2:
            MessageBox.Show("Não é permitido cadastrar um produto sem categoria.","Atenção!");
            break;
        default:
            retValido = true;
            break;
    }

    return retValido;
}

This is one of the possible scenarios.

0

You would then have several layers, for example:

  • Productosdao
  • Products
  • Productosform (I don’t like using controller here, I like mine).

Productosdao would have all CRUD methods in the database.

Products you instance Productsfrom and in the save method you can consult if there is no longer a Product with the same name, if positive launches an Exception (which would be treated in the form).

Productosform you instancia Produtosrn to call the methods of the business rule and deals with the visual part.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.