How to mount a lambda expression and pass it by parameter to a Generic function?

Asked

Viewed 682 times

2

I need to pass two parameters to a generic function that returns database data and select only a few specific columns to display in one DataGridView.

public List<TEntity> GetAll(Expression<Func<TEntity, bool>> Predicate, 
                            Expression<Func<TEntity, TEntity>> Select)
{
       var query = Context.Set<TEntity>()
          .Where(Predicate)
          .Select(Select).ToList();
       return query;
}

For the consultation I will perform, I do not need to pass a Predicate, I just need to pass a Select to return to me:

PessoaId, 
Login, 
Senha,  
UsuarioTipoId, 
Descricao(UsuarioTipo), 
PessoaTipoId, 
Descricao(PessoaTipo). 

If the User is a natural person, display the fields:

NomeCompleto, 
Apelido,
DataNascimento

but if he is a legal person, display the fields:

RazaoSocial, 
NomeFantasia,
DataAbertura

It is a rather complex expression. It is possible to do it and how to Pass it by parameter?

Below follow the classes:

//CLASSES MODEL
public class PessoaModel
    {
        public int PessoaId { get; set; }
        public int PessoaTipoId { get; set; }
        public DateTime DataInclusao { get; set; }

        public virtual PessoaTipoModel PessoaTipo { get; set; }
        public virtual PessoaFisicaModel PessoaFisica { get; set; }
        public virtual PessoaJuridicaModel PessoaJuridica { get; set; }
    }

 public class UsuarioModel : PessoaModel
 {
        public string Login { get; set; }
        public string Senha { get; set; }
        public int UsuarioTipoId { get; set; }

        public virtual UsuarioTipoModel UsuarioTipo { get; set; }

  }

 public class PessoaFisicaModel
 {
        public int PessoaId { get; set; }
        public string NomeCompleto { get; set; }
        public string Apelido { get; set; }
        public DateTime? DataNascimento { get; set; }
        public string CPF { get; set; }

        public virtual PessoaModel Pessoa { get; set; }
 }

 public class PessoaJuridicaModel
 {
        public int PessoaId { get; set; }
        public string RazaoSocial { get; set; }
        public string NomeFantasia { get; set; }
        public DateTime? DataAbertura { get; set; }
        public string CNPJ { get; set; }

        public virtual PessoaModel Pessoa { get; set; }
 }


 //CARREGAMENTO DO DATAGRIDVIEW
 UsuarioRepository UsuarioRepositorio = new UsuarioRepository();
 dgUsuarios.DataSource = UsuarioRepositorio.GetAll();

I needed something more or less like this (Passing parameters):

dgPesquisar.DataSource = UsuarioRepositorio.GetAll(null, u => u.login,  u.Senha, u.NOmeCompleto );
  • you need to do on that GetAll only the Select expression and to define what the Person type is by the field PessoaTipoId what is the value?

  • failed to put the class code: UsuarioTipoModel and PessoaTipoModel

  • Personal ===> 1 P. Physical and 2 P. Legal....

  • Is it Personal or Personal? and lacks both classes UsuarioTipoModel and PessoaTipoModel

  • If your goal is to return the two types of people in your Getall(), with different lists (fields in select), this can’t be done, ie you can’t return a new Personal List and another new Person Juridicamodel at the same time.

3 answers

2

You want to make it simple and flexible or complicated and cast?

using (var context = new MyWonderfulRepositoryContext())
{
    dgUsuarios.DataSource = 
        from pessoa in context.Pessoas
        where /* minha condicao */
        select new PessoaFisicaModel {
            /* monte o seu objecto aqui */
        }
}

But I want to implement the Repository Pattern because someone said it’s a good idea... the DbSet<T> already does and much better than you...

And as for the Unit of Work? the DbContext also already implements this guy.

Ah, but I don’t like Entity Framework and I will sabotage the project to change the ORM for NHibernate in six months.

in this case create a class library with static classes extending the DbContext:

public static PessoasContextExtensions
{
    public static IEnumerable<PessoaFisicaModel> GetPessoasFisicas(this MyWonderfulRepositoryContext context)
    {
        return from pessoa in context.Pessoas
            where /* minha condicao */
            select new PessoaFisicaModel {
                /* monte o seu objecto aqui */
            };
    }
}

and in its application does so.:

dgUsuarios.DataSource = context.GetPessoasFisicas();

and in 6 months you’ll be signing your extensions to GetPessoasFisicas(this MyWonderfulSession session).

0

Hello,

I have prepared an example of generic method for you to use as you asked (or asked if it was possible rs, c# is possible =D )

Generic method:

public IEnumerable<TEntity> Listar<TEntity>(
        Expression<Func<TEntity, bool>> condicao, 
        Expression<Func<TEntity, TEntity>> campos) where TEntity : class
    {
        /*Verifica se possui condição*/
        IQueryable<TEntity> query = condicao != null ? 
                        _bd.Set<TEntity>().Where(condicao) : 
                        _bd.Set<TEntity>();

        /*Verifica se possui campos fitrados*/
        var result = campos != null ? 
                    query.Select(campos).ToList() : 
                    query.ToList();

        return result;
    }

Call for generic method:

public IEnumerable<PessoaFisicaModel> RecuperarPessoasFisicas()
    {
        /*Aqui ele vai buscar todas as pessoas físicas sem a condição where informada*/
        var todasPessoasFisicas = 
            Listar<PessoaFisicaModel>(null, s => new PessoaFisicaModel { PessoaId = s.PessoaId, NomeCompleto = s.NomeCompleto });

        /*Aqui ele vai buscar todas as pessoas que começam com a letra L*/
        var pessoasComLetraL = 
            Listar<PessoaFisicaModel>(
                    w => w.NomeCompleto.StartWith("L"), 
                    s => new PessoaFisicaModel { PessoaId = s.PessoaId, NomeCompleto = s.NomeCompleto });
    }
  • This generic method does not work, because the Where and Select methods do not cause side effects (do not change the state of the object), that is, need to change to query = query.Where(@where). There is also a problem with the use of reservation words, you have to change the variables where and select, respectively to @where and @select.

  • Thanks Gabriel, I updated the method and tested.

0

Look, from what I understand, Getall will get all the people, Physical or Juridicas correct, and what changes are the fields depending on the type?

In this case the days left that seem correct is in the Person class to have this method covered, and implement it in the classes that inherit it. Sort of like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestePessoa
{
    public abstract class Pessoa
    {
        public int PessoaId { get; set; }
        public int PessoaTipoId { get; set; }
        public DateTime DataInclusao { get; set; }

        public abstract List<Pessoa> GetAll(Pessoa filtro);
    }
}

And the classes that implement it

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestePessoa
{
    public class PessoaFisica : Pessoa
    {
        public string NomeCompleto { get; set; }
        public string Apelido { get; set; }
        public DateTime? DataNascimento { get; set; }
        public string CPF { get; set; }

        public override List<Pessoa> GetAll(Pessoa filtro)
        {
            var filtroPEssoaFisica = filtro as PessoaFisica;
            var retorno = new List<Pessoa>();

            //faça sua busca aqui e popule retorno com PessoaFisica fazendo cast para Pessoa


            return retorno;
        }
    }
}

And also:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestePessoa
{
    public class PessoaJuridica : Pessoa
    {
        public string RazaoSocial { get; set; }
        public string NomeFantasia { get; set; }
        public DateTime? DataAbertura { get; set; }
        public string CNPJ { get; set; }


        public override List<Pessoa> GetAll(Pessoa filtro)
        {
            var filtroPessoaJur = filtro as PessoaJuridica;
            var retorno = new List<Pessoa>();

            //faça sua busca aqui e popule retorno com PessoaJuridica fazendo cast para Pessoa


            return retorno;
        }
    }
}

Another way would be to use a delegate of life, https://msdn.microsoft.com/pt-br/library/900fyy8e.aspx

  • Thanks Joe, but then I would have to change the classes... In this case, only the User class would inherit from Pessoa. Personal and Personal are compositional relationships. When I instate the User class, I can already access all the information from the other classes.... I needed something more or less like this (Passing parameters): dgPsearch.Datasource = Usersrepositorio.Getall(null, u => u.login, u.Password, u.Full name );

  • Got it. Anyway, you can change the Getall then to receive a delegate. Then if you want I make the example and step.

  • Gee Joe, if you made an example, I’d really appreciate it... If you want, I can send you a copy of the project...

Browser other questions tagged

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