Arquivo

Archive for julho \27\UTC 2010

Entity Framework + Enumeration

Pessoal, infelizmente nosso querido Entity Framework (EF) não suporta Enumeration (enum), mas não é por causa disso que vamos deixar de usá-los e com isso inventamos truques e artimanhas para fazer com que isso aconteça. 

Para trabalharmos com Enumeration no EF, eu conheço duas formas (e dei nome para elas ainda): 

1.       Encapsulamento de propriedade: é quando se cria um Scalar Property no EF e cria outra propriedade para encapsular essa. 

2.       Casting explicito: é quando se cria um Scalar Property no EF e usa o enum usando casting e tendo que adivinhar que existe um enum para aquela propriedade. 

Bem, agora vamos explanar um pouco mais com passo a passo, vantagens e desvantagens desses dois métodos. Para isso vamos simular um cenário. 

Nosso cenário será de um alimento que pode ser de três tipos, de acordo com o diagrama abaixo. 

Com o objetivo definido vamos ao trabalho. Nos métodos citados irei focar mais na solução do EF com Enumeration, irei considerar que todos saibam criar um EDMX, caso não saibam leia o post http://www.desenvolvendoparaweb.net/profiles/blogs/crud-com-entity-framework. 

Encapsulamento de propriedade

Vantagens:  

·         O programador codifica como codificava antes. 

·         Obriga a propriedade informar uma Enumeration. 

Desvantagens 

·         Foge do padrão de nomenclatura no EF. 

·         Infere a integridade da classe como está no modelo. 

Passo a passo 

1.       Crie sua Enumeration TipoAlimentoEnum como segue no código abaixo. 

public enum TipoAlimentoEnum : short
{
    Satvico = 1,
    Rajasico = 2,
    Tamasico = 3
} 

2.       Crie seu Entity Framework com a classe Alimento normalmente, mas na propriedade Tipo, crie em lowerCase e os atributos Getter e Setter com valor Private. 

 

  

3.       Crie uma classe partial de Alimento e implemente a propriedade Tipo (em CamelCase) como Enumeration. 

public partial class Alimento
{
    public TipoAlimentoEnum Tipo {
        get { return (TipoAlimentoEnum)this.tipo; }
        set { this.tipo = (short)value; }
    }
}

4.       Pronto, Agora é só testar. 

using (var ctx = new Model1Container())
{
    var alimento = new Alimento()
    {
        Descricao = "Cenoura",
        Tipo = TipoAlimentoEnum.Satvico
    };

    ctx.AddToAlimentoSet(alimento);
    ctx.SaveChanges();
}

  

Para as pessoas que utilizam POCO é basicamente a mesma coisa, a diferença é que o código da entidade ficará dessa forma: 

public partial class Alimento
{
    public virtual int AlimentoId { getset; }
    public virtual string Descricao { getset; }
    private virtual short tipo { getset; }

    public TipoAlimentoEnum Tipo
    {
        get { return (TipoAlimentoEnum)this.tipo; }
        set { this.tipo = (short)value; }
    }
}

Essa solução termina aqui e espero q tenham entendido. Agora vamos o próximo método. 

Casting explicito

Vantagens:  

·         Permanece com a nomenclatura das propriedades do EF. 

Desvantagens 

·         O programador deve adivinhar que tal propriedade existe uma Enumeration. 

·         Infere a integridade da classe como está no modelo. 

Passo a passo 

1.       Crie sua Enumeration TipoAlimentoEnum de acordo com o método anterior. 

2.       Crie seu Entity Framework com a classe Alimento normalmente de acordo com o método anterior. 

3.       Use a Enumeration com casting. 

using (var ctx = new Model1Container())
{
    //insere
    var alimento = new Alimento()
    {
        Descricao = "Cenoura",
        Tipo = (short)TipoAlimentoEnum.Satvico
    };

    ctx.AddToAlimentoSet(alimento);
    ctx.SaveChanges();
}

  

Os dois métodos de ser trabalhar com EF com Enumeration que eu conheço são esses, espero ter ajudado. 

Abraços.

Anúncios
Categorias:.NET Tags:, , ,

LINQ: Está contido em outra coleção?

Pessoal,

Tive uma necessidade imensa de verificar se estavam contidos alguns elementos de uma coleção em outra coleção, e isso utilizando LINQ com tipos complexos. Quem conhece o LINQ sabe que não dá para comparar dois tipos complexos, logo temos q comparar os tipos primários.

Vou apresentar nesse post duas formas fáceis de comparar se os elementos de uma coleção estão contidos em outra coleção de tipos complexos.

Meu cenário é o seguinte:

Tenho uma classe Produto:

class Produto {
    public int ProdutoID { getset; }
    public string Descricao { getset; }
    public int Quantidade { getset; }

    public Produto(int produtoID, string descricao, int quantidade)
    {
        ProdutoID = produtoID;
        Descricao = descricao;
        Quantidade = quantidade;
    }
}

Dessa classe tenho duas listas:

var produtos = new []{ 
    new Produto(1"produto 1"2),
    new Produto(2"produto 2"16),
    new Produto(3"produto 3"11),
    new Produto(4"produto 4"5),
    new Produto(5"produto 5"22)};
var produtos2 = new []{ 
    new Produto(1"produto 1"2),
    new Produto(2"produto 2"16),
    new Produto(5"produto 5"22)};

Eu quero eu verificar se os elementos da coleção produtos2 estão contidos na coleção produtos. E eu não posso simplesmente inserir no LINQ o método Contains e comparar as duas instâncias, como apresentado abaixo:

var result = (from p1 in produtos where produtos2.Contains(p1) select p1).ToArray();

Vai me retornar nada, devido a identidade de cada objeto. Visto a necessidade de comparar as propriedades entre as coleções, busquei e busquei formas de fazer isso e não achei, foi ai então que fiz minha própria solução, na verdade duas.. rsrs.

Criei uma classe que implementa a interface IEqualityComparer para usar no método Contains e criei meu próprio ContainsByProperty.

A classe com a implementação do IEqualityComparer, ficou da seguinte forma:

class PropertyEqualityComparer<TSource> : IEqualityComparer<TSource>
{
    Func<TSource, object> _keySelector;

    public PropertyEqualityComparer(Func<TSource, object> keySelector)
    {
        _keySelector = keySelector;
    }

    public bool Equals(TSource x, TSource y)
    {
        return _keySelector(x).Equals(_keySelector(y));
    }

    public int GetHashCode(TSource obj)
    {
        return obj.GetHashCode();
    }
}

Podendo ser usado da seguinte forma:

var result = (from p1 in produtos
      where produtos2.Contains(p1, 
           new PropertyEqualityComparer<Produto>(p => p.ProdutoID)) select p1).ToArray();

E o método ContainsByProperty (que eu preferi), ficou da seguinte forma:

public static bool ContainsByProperty<TSource, TKey>(this IEnumerable<TSource> source, TSource value, Func<TSource, TKey> keySelector) 
{
    foreach (TSource item in source)
       if (keySelector(value).Equals(keySelector(item)))
           return true;
    return false;
}

Podendo ser usado da seguinte forma:

var result2 = (from p1 in produtos
               where produtos2.ContainsByProperty(p1, p => p.ProdutoID)
               select p1).ToArray();

A referencia que mais me ajudou a implementar esses métodos foi o http://stackoverflow.com/questions/1082624/isorderedby-extension-method

Espero que esses códigos ajudem vocês assim como me ajudou e muito. Qualquer coisa pode comentar ou mande um e-mail, estarei à disposição.

Abraços