Specification Pattern, dúvidas!

148 views
Skip to first unread message

Alexsandro

unread,
Apr 14, 2013, 11:18:36 PM4/14/13
to dotnetar...@googlegroups.com
Estive dando uma olhada em cima deste pattern mais precisamente sobre esta implementação https://linqspecs.codeplex.com/

Estou com uma duvida que não consegui descobrir que é: Como combinar as specification? se é que é correto combina-las....

Vejam o exemplo:

        public static ISpecification<Destaque> ComPreco()
        {
            DirectSpecification<Destaque> adHocSpecification;

            Expression<Func<Destaque, bool>> spec = s => s.Produto.Precos.AsQueryable().Where(PrecoSpecification.ComPeriodoValido().SatisfiedBy()).Any();

            var specification = new DirectSpecification<Destaque>(spec);

            return specification;
        }

Em negrito na linha a cima, tentei combinar com outra Specification, porem no teste eu recebom esta exception:

System.InvalidOperationException: Erro interno 1025 do .NET Framework Data Provider.


Eu até imagino o motivo do erro, mas não tenho certeza. Imagino que por usar Expression<T> eu chamando SatisfiedBy eu invoco o Predicate antes de passar para o Entity Framework. Se eu estiver certo do erro, qual é melhor maneira então de combinar as regras?

Marcus Alexandre Silva

unread,
Apr 15, 2013, 5:58:07 AM4/15/13
to dotnetar...@googlegroups.com

https://linqspecs.codeplex.com/SourceControl/changeset/view/3f6fa405808e#LinqSpecs/ExpressionCombining/Utility.cs

andSpecification e orSpecification.

--
Você recebeu esta mensagem porque faz parte do grupo .Net Architects hospedado no Google Groups.
Para postar envie uma mensagem para dotnetar...@googlegroups.com
Para sair do grupo envie uma mensagem para dotnetarchitec...@googlegroups.com
Para mais opções visite o grupo em http://groups.google.com/group/dotnetarchitects?hl=pt-br
---
Você está recebendo esta mensagem porque se inscreveu no grupo ".Net Architects" dos Grupos do Google.
Para cancelar a inscrição neste grupo e parar de receber seus e-mails, envie um e-mail para dotnetarchitec...@googlegroups.com.
Para obter mais opções, acesse https://groups.google.com/groups/opt_out.
 
 

Alexsandro

unread,
Apr 15, 2013, 10:41:22 AM4/15/13
to dotnetar...@googlegroups.com
Ola @Marcus, não pode com andSpecification e nem orSpecification porque são tipos diferentes uma vez que quero combinar.

Ex:
No codigo mencionado tem a seguinte assinatura:

public static ISpecification<Destaque> ComPreco()

E neste outro que desejo combinar tem outra assinatura:
PrecoSpecification.ComPeriodoValido() --> public static ISpecification<Preco> ComPeriodoValido()


Se eu tentasse combinar com new AndSpecification<Preco>(PrecoSpecification.ComPeriodoValido(), ????< ISpecification<Destaque> é tipo incopativel>??????????? );

E agora?

Marcus Alexandre Silva

unread,
Apr 15, 2013, 10:55:34 AM4/15/13
to dotnetar...@googlegroups.com
Acho que voce não pegou ainda o ritmo da coisa, mas serial algo assim pelo seu exemplo:

Specification<Destaque> and = new PrecoSpecification { Preco = 10.00 }
                          & new DestaqueSpecification { Destaque = "?" };

Alexsandro

unread,
Apr 15, 2013, 12:11:19 PM4/15/13
to dotnetar...@googlegroups.com
Realmente estou fazendo confusões e estou tentando esclarecer.

Explicando melhor o cenário a gente vai descobrir onde estou errando. Seguinte:

Possuo produtos. Possuo produtos que contem preço. Posso produtos que contem preço e que tambem é destaque.

Agora tempo os seguites casos:
Qual produto que possui preço?
Qual produto que NÃO possui preço?
Qual produto que possui preço e é um destaque?


Todos meus Specification são metodos estáticos. Cada metodo estático possuiem criterios de filtragem.
O exemplo abaixo contem o criterio de validação de preço válido:

    public class PrecoSpecification
    {

        public static ISpecification<Preco> ComPeriodoValido()
        {
            DirectSpecification<Preco> leftAdHocSpecificationComComeco;
            DirectSpecification<Preco> rightAdHocSpecificationSemFim;
            DirectSpecification<Preco> rightAdHocSpecificationComFim;

            Expression<Func<Preco, bool>> CriteriaComPrecoIncial = i => i.DataInicial <= DateTime.Today;
            Expression<Func<Preco, bool>> CriteriaSemPrecoFinal = i => i.DataFinal == null;
            Expression<Func<Preco, bool>> CriteriaComPrecoFinal = i => i.DataFinal >= DateTime.Today;

            leftAdHocSpecificationComComeco = new DirectSpecification<Preco>(CriteriaComPrecoIncial);
            rightAdHocSpecificationSemFim = new DirectSpecification<Preco>(CriteriaSemPrecoFinal);
            rightAdHocSpecificationComFim = new DirectSpecification<Preco>(CriteriaComPrecoFinal);

            AndSpecification<Preco> composite1ComComecoSemFim = new AndSpecification<Preco>(leftAdHocSpecificationComComeco, rightAdHocSpecificationSemFim);
            AndSpecification<Preco> composite2ComComecoComFim = new AndSpecification<Preco>(leftAdHocSpecificationComComeco, rightAdHocSpecificationComFim);

            OrSpecification<Preco> composite = new OrSpecification<Preco>(composite1ComComecoSemFim, composite2ComComecoComFim);

            return composite;
        }
    }



Agora eu tento combina-lo com DestaqueSpecification:

        public static ISpecification<Destaque> ComPreco()
        {
            DirectSpecification<Destaque> leftAdHocSpecification;

            Expression<Func<Destaque, bool>> leftSpec = s => s.Produto.Precos.AsQueryable().Where(PrecoSpecification.ComPeriodoValido().SatisfiedBy()).Any();

            var specification = new DirectSpecification<Destaque>(leftSpec);

            return specification;
        }



Veja, sao tipos diferentes, preço e destaque, para acessar preço eu tenho que navegar entre as propriedades.

No seu exemplo é feito a instancia e usado um operador and lógico, pra isto ao menos dar certo, esta duas classes teria que herdar de ISpecification<Entity>, que é que nao faço hoje. será que teria entao que fazer?

Este meu exemplo peguei ao ler o livro N-Layered Domain-Oriented Architecture Guide da MS. https://microsoftnlayerapp.codeplex.com/


Valew @Marcus!

Marcus Alexandre Silva

unread,
Apr 15, 2013, 1:24:43 PM4/15/13
to dotnetar...@googlegroups.com
Acho que a confusão ai são suas entidades. Preço e Destaque não são entidades, são Atributos de Produto. De acordo com seu cenário acho que as coisas seriam +- assim:

public class Product
{
  public decimal Price { get; set; }
  public bool IsFeatured { get; set; }
}

public class WithPrice : Specification<Product>
{
  public override Expression<Func<Product, bool>> IsSatisfiedBy()
  {

    return a => a.Price > 0;
  }
}

public class WithoutPrice : Specification<Product>
{
  public override Expression<Func<Product, bool>> IsSatisfiedBy()
  {

    return a => a.Price == 0;
  }
}

public class IsFeatured : Specification<Product>
{
  public override Expression<Func<Product, bool>> IsSatisfiedBy()
  {

    return a => a.IsFeatured;
  }
}

public static class Scenario
{
  public static void Cases()
  {
    //com preço:
    Specification<Product> withPrice = new WithPrice();

    //sem preço
    Specification<Product> withoutPrice = new WithoutPrice();

    //sem preco e é destaque
    Specification<Product> withoutPriceandFeatured =
      new WithoutPrice() & new IsFeatured();
  }
}


Alexsandro

unread,
Apr 15, 2013, 2:02:40 PM4/15/13
to dotnetar...@googlegroups.com
Ta acontecendo uma confusão ai.. rs...

O negocio é mais complexo devido as regras, preço é uma entidade sim, porque preço é um atributo multivalorado. Um produto tem uma coleção de preços.

Destaque é praticamente mesmo caso, um produto pode ser 3 tipos de destaque, inclusive os 3 tipos ao mesmo tempo e quem diz isto é a entidade de Destaque.
As entidades são:

public class Product
{
  public IList<Price> Price { get; set; }
}

public class Featured
{
  public Local Type { get; set; }
  public Product Product { get; set; }
  public DateTime StartDate { get; set; }
  public DateTime EndDate { get; set; }
}

public class Price
{
  public PriceType Type { get; set; }
  public Product Product { get; set; }
  public decimal Value { get; set; }
  public DateTime StartDate { get; set; }
  public DateTime EndDate { get; set; }
}


Esta ai são as regras do cenario, se fosem atributos, não me parece que funcionaram com este cenario.


Valew!!

Marcus Alexandre Silva

unread,
Apr 15, 2013, 2:38:49 PM4/15/13
to dotnetar...@googlegroups.com
Cara...

Seu domínio esta bastante confuso pra mim :)
Preço seria Lista de Preço?
Destaque seria Lista de Produtos em Destaque?

As perguntas seriam:
Qual produto que possui  alguma lista de preço? 

Qual produto que NÃO possui nenhuma lista de preço? OU
Qual produto não faz parte da lista x de preço?
Qual produto que esta na lista de preço X e é um destaque Y?

Além disto estou sentindo falta de Surrogates Keys ai...

Me ajuda ai pra ver se eu consigo te ajudar :)



Alexsandro

unread,
Apr 15, 2013, 3:51:52 PM4/15/13
to dotnetar...@googlegroups.com
Rs... vamos la:

Uma instancia de Produto é um objeto contem o atributo Preços onde é uma lista de Preço.
Uma instancia de Destaque é um objeto contendo um atributo Produto.

As perguntas corretas seriam:
1 - Qual produto que possui algum preço válido dado seu atributo Preços(lista de preço)? ( Criterio: Conter pelo menos 1 preço na lista onde o ultimo deve-se encaixar no range data de hoje. Se a lista dele for 0 então ela ja é descartado )
2 - Qual produto que NÃO possui preço válido dado seu atributo Preços(lista de preço)? ( Criterio: Lista com 0 itens OU a negação do criterio a cima  )
3 - Dado uma listagem de Destaque com tipo=Principal, Quais produtos destas listagem contem preço válido? ( Criterio: Todos atributos Produto da lista de Destaque, devem obdecer o criterio 1  )

Sobre as Keys, todos as 3 entidades cotem uma ID único.. so foi omitido, mas pode ficar tranquilo. vamos chamar de Id.

Ficou mais claro agora?

Obrigadão!!!!! @Marcos :)

matheus...@uniderp.edu.br

unread,
Apr 16, 2013, 11:25:32 AM4/16/13
to dotnetar...@googlegroups.com
Talvez para dar uma clareada você poderia dar uma olhada no exemplo que existe no livro Professional ASP.NET Design Patterns, la tem um exemplo muito bom de Specification junto com o pattern Composite.

Este é o link para download dos fontes de exemplo do livro:


Baixa o "Chapter 05 code downloads", ele vai baixar um zip, tem um exemplo na pasta ASPPatterns.Chap5.Specification.

Só não sei se vai funcionar junto com o LINQ to Entities, creio que para isso você terá que substituir os retorno final do specification para um tipo Func<T, bool>, ou coisa do tipo. Boa Sorte!

Alexsandro

unread,
Apr 16, 2013, 11:50:04 AM4/16/13
to dotnetar...@googlegroups.com
Opa @Matheus!!

Obrigado pelo exemplo, estou vendo aqui, ele faz um exemplo com Custumers, mas minha dúvida é sobre composição de entidades diferentes, é isto que não encontro em lugar nenhum, até estou achando que isto que desejo não faz parte de Specification Pattern.

Meu caso é:
Eu tenho 3 Specification, um de Preço, um de Produto e um de Destaque.


Seu caso é descobrir como usa-las em conjunto se o .NET Framework da um erro maluco de: System.InvalidOperationException: Erro interno 1025 do .NET Framework Data Provider.

Valew!!

Marcus Alexandre Silva

unread,
Apr 16, 2013, 11:57:56 AM4/16/13
to dotnetar...@googlegroups.com
Bom.... Eu sou péssimo para explicações :)

O que tenho tentado mostrar é que, com o padrão Specification mais precisamente com o LinqSpecs você não precisa (e até não deve) trazer mais de um Objeto no Resultado, a menos que seu repositório saiba devolver um objeto Response { Product[], Prices[], Others... } . Você passa n parametros de objetos para o que seria o Where de Sua Sql. O Resultado é um Objeto de um mesmo tipo, sempre.
É +- quando voce faz uma Consulta com Inner Join entre 3 tabelas. O resultado é '1' View, sempre!






--

Alexsandro

unread,
Apr 16, 2013, 12:09:59 PM4/16/13
to dotnetar...@googlegroups.com
Sem problemas @Marcos, o que vale a discursão. :)

Este caso ao de trazer mais de um Objeto está até resolvido, eu tenho minhas Specfication funcionando. Mas o que me incomoda é ter que ficar repetindo codigo de criterios, isto nao me parece legal.

Se eu pudesse casar as Specfications para respeitar o DRY......

Ai que ta o caso ainda sem reposta pois das formas que tentei o .NET me traz um erro interno e eu tenho quase certeza que tem ligação ao Expression<T>.

Marcos Tupan

unread,
Apr 29, 2013, 10:07:40 AM4/29/13
to dotnetar...@googlegroups.com
Bom dia,

não fui muito a fundo em busca de maneiras de reutilização, acredito que existam varias tecnica de reutilização para Linq, nos projeto que trabalhei utilizo da seguinte forma: 

    public class Product
    {
        public decimal Preco { get; set; }
        public bool Ehdestaque { get; set; }
    }

    public static class Products
    {
        public static List<Product> ListarProdutosEmDestaque()
        {
            IQueryable<Product> meusProdutos = (new List<Product>()).AsQueryable();
            return meusProdutos.
                Destaques().
                ToList();
        }

        public static List<Product> ListarProdutosNoIntervaloDePreco(decimal menorValor, decimal maiorValor)
        {
            IQueryable<Product> meusProdutos = (new List<Product>()).AsQueryable();
            return meusProdutos.
                PrecoMaiorIgualQue(menorValor).
                PrecoMenorIgualQue(maiorValor).
                ToList();
        }

        public static IQueryable<Product> Destaques(this IQueryable<Product> produtos)
        {
            return produtos.Where(x => x.Ehdestaque);
        }

        public static IQueryable<Product> PrecoMaiorIgualQue(this IQueryable<Product> produtos, decimal valor)
        {
            return produtos.Where(x => x.Preco >= valor);
        }

        public static IQueryable<Product> PrecoMenorIgualQue(this IQueryable<Product> produtos, decimal valor)
        {
            return produtos.Where(x => x.Preco <= valor);
        }
    }

Espero que ajude,
Att,
-- 
Marcos Tupan
|41| 9147-8335
Reply all
Reply to author
Forward
0 new messages