terça-feira, abril 01, 2008

Sistema de Notícias "Digg like" desenvolvido com db4o

Pessoal.
Estou disponibilizando agora a projeto final de graduação desenvolvido pelo aluno Cléverton Silva, sob minha orientação, no curso de Ciência da Computação na Universidade Federal do Espírito Santo.

Trata-se de um sistema de notícias no estilo "Digg", com uma espécia de rankeamento automatico das notícias, baseado em filtragem colaborativa.

O projeto foi desenvolvido utilizando as tecnologias .NET 2.0 e db4o.

Read this doc on Scribd: SIWEP - Digg Like com Db4o

sexta-feira, abril 13, 2007

Especificações do DB4O




Especificações sobre o DB4O que podem ser encontradas na documentação

quinta-feira, abril 12, 2007

Native Queries

DB4O - Data Base For Objects

Native Queries – Parte 1 (por Jeudí Prando)

Antes de iniciar o artigo irei definir uma classe para servir de exemplo nos tópicos que serão apresentados.


public class Pessoa
{
private string _nome;
private string _sobreNome;
private string _sexo;

public Pessoa()
{
this._nome = “”;
this._sobreNome = “”;
this._sexo = “”;
}

public Pessoa(string nome, string sobreNome, string sexo)
{
this._nome = nome;
this._sobreNome = sobreNome;
this._sexo = sexo;
}

public string Nome
{
get{ return this._nome; }
set{ this._nome = value; }
}

public string SobreNome
{
get{ return this._sobreNome; }
set{ this._sobreNome = value; }
}

public string Sexo
{
get{ return this._sexo; }
set{ this._sexo = value; }
}
}


Pronto agora que a nossa classe modelo esta definida vamos ao que interessa.

DB4O nos fornece três tipos de pesquisa

• Query-By-Example (QBE)
• SODA API.
• Native Queries (NQ)

Como neste artigo o meu foco é o Native Querie não falarei sobre os outros tipos de pesquisa

O tipo de pesquisa Native Queries (NQ) é o sistema de pesquisa principal do DB4O, recomendada para o uso geral.

Não seria agradável se pudesse realizar pesquisas utilizando as regras da linguagem de programação que você esta utilizando?
Não seria agradável se todas as suas pesquisas fossem fortemente tipadas?
Não seria agradável se você pudesse utilizar todo o poder da Linguagem Orientada a Objeto para realizar as suas pesquisas?

Utilize Native Queries(NQ)!

Native Queries é a principal sistema de pesquisa do DB4O e é o sistema de pesquisa recomendado para utilizar em sua aplicação.
As pesquisas em Native Querie utilizam a semântica da linguagem de programação que você esta utilizando, é uma escolha segura para o futuro.
Native Queries (NQ) é fortemente tipado.
Native Queries estão disponíveis para todas as plataformas suportadas por DB4O.

Native Querie fornecem a habilidade de executar uma ou mais linhas de código de encontro a todos as instancias de um objeto em um repositório de objetos
As expressões de Native Queries devem retornar verdadeiro para recuperar os objetos que esta sendo testado pela expressão.
DB4O tentará otimizar as expressões de Native Queries e executá-la de encontro aos índices e a busca é otimizada de forma a instanciar de verdade
somente os objetos que irão fazer parte da lista.

Essas expressões são exatamente as mesmas que você utiliza em um "if", por exemplo, se retornar verdadeiro o objeto é adicionado a lista se retornar
falso o objeto não é adicionado a lista.

Um exemplo de Expressões de Native Queries:


IList iLista = db.Query(delegate(Pessoa pessoa)
{
return (pessoa.Nome.Contains("a"));
}
);



Esta é a expressão da nossa Native Querie utilizada neste exemplo:


delegate(Pessoa pessoa)
{
return (pessoa.Nome.Contains("a"));
}


Esta expressão juntamente com o metodo Query, esta dizendo que é para percorrer todos os objetos do tipo Pessoa "delegate(Pessoa pessoa)" dentro do nosso repositório de objetos.

A cada objeto percorrido será instanciado no atributo pessoa dentro do delegate"delegate(Pessoa "pessoa")", e será testado conforme o código que vem da sua própria linguagem de programação,
no nosso caso, procura por pessoas que contenham a letra "a" no nome "pessoa.Nome.Contains("a")", se o objeto pessoa atualmente instanciado em "pessoa" tiver a letra "a" no nome a expressão
retornará verdadeiro, fazendo com que o atual objeto pessoa faça parte da lista que será montada ao termino do percorrer e validar todos os objetos do nosso repositório de objetos, no nosso
caso os objetos do tipo pessoa, gerando assim o nosso famoso "Result Set".

vamos ver alguns exemplos, utilizando nossa classe modelo:

/// vamos instanciar algumas pessoas

Pessoa fulano = new Pessoa();
fulano.Nome = "Fulano";
fulano.Sexo = "M";

Pessoa beltrano = new Pessoa("Beltrano","","M");
Pessoa ciclana = new Pessoa("Ciclana","","F");

/// vamos iniciar a comunicação com o nosso repositório de objetos
IObjectContainer db = Db4oFactory.OpenFile("dados.yap");

/// persistindo as pessoas instanciadas
db.set(fulano);
db.set(beltrano);
db.set(ciclana);


agora vamos recuperar todas as pessoas do sexo Feminino, utilizado Native Querie


IList lista = db.Query(delegate(Pessoa pessoa){ return pessoa.Sexo = "F"});


neste caso seria retornado somente o objeto Pessoa "ciclana"

se eu quisesse utilizar o poder que se tem de uma linguagem orientada a objeto poderíamos fazer um Método que busque
todas as pessoas de um sexo especificado. Ex:


public List RecuperarListaPessoaDeterminadoSexo(string sexo)
{
/// vamos iniciar a comunicação com o nosso repositório de objetos
IObjectContainer db = Db4oFactory.OpenFile("dados.yap");

/// vamos recuperar as pessoas de um sexo especificado através do parâmetro "sexo"
return new List(db.Query(delegate(Pessoa pessoa){ return pessoa.Sexo = sexo}));
}


agora ao executar o método


RecuperarListaPessoasDeterminadoSexo("M");


seria retornado uma lista contendo os objetos Pessoas: Fulano e Beltrano

poderíamos estender este artigo realizando muitas variações de consulta utilizando Native Queries, mas esta variação
é devida a liberdade que a linguagem orientada a objeto te dá...

Por exemplo poderíamos utilizar a ordenação no List, buscar pessoas que iniciem ou não contenham sobre nome e assim
por diante...

Mas o meu objetivo neste artigo é passar um pouco de noção do que é Native Querie, como Utilizar, como montar expressões,
como o mesmo funciona e não falar sobre orientação a objeto apesar do assunto esta contido em Native Queries

espero ter ajudado alguém! rss

Boa Sorte!

sexta-feira, novembro 24, 2006

Simples, mas prático

Galera, vou postar um exemplo bem simples de como realizar
dois tipo diferentes de busca aproximada utilizando metodos
nativos do DB4o, sem precisar fazer nada de novo.

Nossa classe de dominio:


public class Regra {
private String padrao;
private String tratamento;
private String modulo;
public String getModulo() {
return modulo;
}
public void setModulo(String modulo) {
this.modulo = modulo;
}
public String getPadrao() {
return padrao;
}
public void setPadrao(String padrao) {
this.padrao = padrao;
}
public String getTratamento() {
return tratamento;
}
public void setTratamento(String tratamento) {
this.tratamento = tratamento;
}
}


Parte 2: DAO

Nossa classe DAO:



import com.db4o.Db4o;
import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.db4o.query.Constraint;
import com.db4o.query.Query;

import dominio.Palavra;
import dominio.Regra;

public class DAORegra {

public ObjectContainer db;

public DAORegra(){

}

public void open(String idioma){
this.db = Db4o.openFile("memoria/regras/"+idioma+".regras");
}

public void close(){
this.db.close();
}

public void store(String padrao, String tratamento,String modulo){
Regra regra = new Regra();

if(!padrao.equalsIgnoreCase("") && !tratamento.equalsIgnoreCase("")){


regra.setPadrao(padrao.toUpperCase());

ObjectSet result = db.get(regra);

if(result.size() != 0){
regra = (Regra) result.next();
}

regra.setModulo(modulo);
regra.setPadrao(padrao.toUpperCase());
regra.setTratamento(tratamento.toUpperCase());
db.set(regra);
db.commit();
}


}



public String[] getRegras(String padrao, String tratamento,String modulo){
Regra regra = new Regra();

Query query=db.query();
query.constrain(Regra.class);

Constraint constrPadrao=null,constrModulo=null,constrTratamento=null;

constrPadrao=query.descend("modulo").constrain(modulo);


if(!padrao.equalsIgnoreCase("")){
constrPadrao=query.descend("padrao").constrain(padrao.toUpperCase()).startsWith(true);
}

if(!tratamento.equalsIgnoreCase("")){
constrPadrao=query.descend("tratamento").constrain(tratamento.toUpperCase()).startsWith(true);
}

ObjectSet result = query.execute();


String[] regras = new String[result.size()];

if(result.size() == 0){
regras = new String[1];
regras[0] = "Nao Encontrada nenhuma ocorrência";
}else{
for(int i=0;i
regra = (Regra) result.next();
regras[i] = regra.getPadrao()+" : "+regra.getTratamento();
}
}

return regras;
}

public void delete(String padrao, String tratamento,String modulo){
Regra regra = new Regra();
regra.setModulo(modulo);

if(!padrao.equalsIgnoreCase("") && !tratamento.equalsIgnoreCase("")){

regra.setPadrao(padrao.toUpperCase());
regra.setTratamento(tratamento.toUpperCase());

ObjectSet result = db.get(regra);

if(result.size() != 0){
regra = (Regra) result.next();
db.delete(regra);
db.commit();
}
}

}

public Regra existeRegraIgual(String padrao){
Regra regra = new Regra();

Query query=db.query();
query.constrain(Regra.class);

Constraint constr=null;
constr=query.descend("padrao").constrain(padrao);

ObjectSet result = query.execute();

regra = (Regra) result.next();

return regra;
}

public int existeRegra(String padrao){
Regra regra = new Regra();

Query query=db.query();
query.constrain(Regra.class);

Constraint constr=null;
constr=query.descend("padrao").constrain(padrao.toUpperCase()).startsWith(true);

ObjectSet result = query.execute();


return result.size();
}
}


Utilizando isso:
(
frame.getPalavras() retorna palavras é um vetor Palavra[], presumam isso):



public class aplicarRegras {

public aplicarRegras(frameGeral frame){
Palavra palavraAtual;
Regra regraAtual;
Palavra[] palavras = frame.getPalavras();
String bufferGlobal="",regra="", pilha="", candidataRegra="", idioma=frame.getIdiomaDeEntrada();
DAORegra daoRegras = new DAORegra();
daoRegras.open(idioma);
int i = 0;
while(i palavraAtual = palavras[i];
if(regra.equals(""))
candidataRegra = palavraAtual.getClasseGramatical();
else
candidataRegra = regra+" "+palavraAtual.getClasseGramatical();
if((!palavraAtual.getClasseGramatical().equalsIgnoreCase("Nao Encontrada"))
&&(daoRegras.existeRegra(candidataRegra)>0)){
regra = candidataRegra;
if(pilha.equals(""))
pilha = palavraAtual.getGrafia();
else
pilha += " "+palavraAtual.getGrafia();
}else{

if(!pilha.equals("")){
regraAtual = daoRegras.existeRegraIgual(regra);
if(regraAtual != null){
bufferGlobal+="<"+regraAtual.getModulo()+">"+pilha+"";
}else{
bufferGlobal+=pilha+" ";
}
}
bufferGlobal+=palavraAtual.getGrafia()+" ";
pilha="";
regra="";
}
i++;
}
daoRegras.close();
frame.setTextoMarcado(bufferGlobal);
}


}

sexta-feira, novembro 17, 2006

Erros Comuns - Parte 1

Neste meu primeiro post venho trazer a tona erros mais comuns entre usuários iniciantes. Nesta minha primeira semana de uso detectei alguns erros cumuns de desenvolvimento que cometi e me fez perder certo tempo, e como percibi que são normais de se cometer quando se aprende a usar uma nova tecnologia pretendo passar este conhecimento a usuários iniciantes para que estes ganhem tempo !!!

Chamei de Erros mais Comuns - Parte 1 devido a minha pouca experiência neste momento e a poucas possíbilidades exploradaas ainda sobre o uso do db4o. Em breve acredito cometer novos erros que possam ser digno de um segundo post, e para no futuro condençar num artigo mais completo e bem escrito.


Construtor não Vazio x Pesquisa FullObjects:

Chamo aqui de pesquisa FullObjects aquela que retorna todos os elementos de uma classe que se encontra armazenadas no db4o. (pode-se fazer uma analogia próxima ao Select * from Tabela )

Para se buscar todos os objetos da classe usando o método Get deve-se preencher todos os campos da classe com valores nulo.

Erro Comum: O construtor de uma classe pode preencher um conjunto de atributos com informações padrões.

Resultado deste Erro: O Db4o rretornará as informações somente dos objetos que não tiveram estes atributos alterados, deixando muitos objetos de fora.

Correção Sugerida: O objeto deve possuir um Construtor (ou um método) que seta nullo em todos os atributos não constantes do objeto.

Inserir x Alterar

Quando agente quer inserir um objeto, agente cria um objeto vazio, preenche as inforções e salva. Quando agente pretende alterar devemos buscar o objeto no banco, editar suas informações e recoloca-lo no banco.

Erro Comum:

Quando agetne utilizava o SGBD relacional agente pegava o objeto que nos era passado por outra camada da aplicação, desmenbramos em um comando SQL e executamos. Quando agente recebe este objeto da camada de controle (ou outra dependedo da arquitetura) a ideia intuitiva é usar o metodo Set para salvar as alterações.


Resultado deste Erro: O objeto passado cria uma nova informação no db4o, em vez de alterar a existente como foi o desejado.


Correção Sugerida: Deve se usar o método Get para obter o objeto do banco que deseja se editar, alterar as informações que forem necessárias e usar o método Set para salvá-lonovamente no Banco.



Conclusão:
São algumas sugestões que possam facilitar a vida de quem está iniciando, porém muitas delas possuem melhores soluções, Deixo então o convite para todos os interessados em estudar este novo paradigma que partipem do grupo db4oBrasil dando dicas e sugestões e efetuando críticas construtivistas.


Abraços a Todos
Bernard C. Pereira

quinta-feira, novembro 09, 2006

Estamos no Imasters

Olá pessoal, a partir de hoje estamos representados no portal imasters. O primeiro artigo que mandei nada mais é do que as informações fornecidadas no próprio site db4o resumidas. Espero receber sugestões de vocês para os próximos artigos.

[]'s

terça-feira, outubro 31, 2006

Popularizando o DB4O

O Eduardo (EddieStone) apresentou uma idéia que eu imediatamente gostei: "Vamos criar um curso para ensinar a utilizar o DB4O". Ontem,em uma conversa com meu orientador do mestrado apresentamos a ideia, e o professor complementou com outra ideia interessante: "Vamos oferecer uma discipĺina optativa de Tópicos Especiais em Banco de Dados abordando esse tema."

Bem, resumindo, provavelmente vamos no proximo semetre ter na Ufes uma disciplina onde poderemos apresentar o DB4O para os alunos interessados.. eu particularmente fiquei muito animado com a idéia!!!

Tomara que o resultado disso seja que muitos alunos nossos utilizem o DB4O em seus projetos de graduação!!!!!!!!!!!!!!!!!!

DB4O Compartilhado

A UFES tem se mostrado um terreno fértil para o desenvolvimento
de sistemas que utilizam o DB4O como unica base de dados,
a pergunta que fica é "como vai ser quando quisermos integrar os dados?".

Existe uma proposta para criar um portal, integrando varios sistemas
web. Esses sistemas estão sendo construidos totalmente baseados no
paradigma OO, logo, não existe motivo para que a abordagem mude
quando chega a hora de tratar sobre a persistência.

Um ponto que vem me preocupando um pouco é a questão de como
vai ficar o desempenho quando precisarmos compartilhar as bases de dados.
Será que vamos conseguir desenvolver as ferramentas que possibilitem
que todas as aplicações utilizem um servidos DB4O da mesma forma que utilizariam um SGDB relacional.

Minha opinião é que o resultado será muito positivo, mas realmente
vou ficar muito mais tranquilo quando fizermos os primeiros testes
com varias aplicações diferentes acessando um unico servidor DB4O.

Data Access Objects com DB4O : Continuando

Primeiro gostaria de destacar o post de sri_canesh , pois quando nos deparamos com db4o e percebemos a sua importancia, queremos logo usá-lo em todo lugar, e esquecermos para sempre dos bancos relacionais, quando na verdade, não devemos fazer isso.

Agora continuando o post sobre o "pattern" Data Access Objects com db4o, vamos ver como ficaria uma subclasse DAO (alguns chamam de classe sombra).

Primeiro, vamos criar uma classe exemplo da camada de domínio:


namespace Db4oBrasil.Dominio
{
  public class Usuario
  {
    private string _nome;
    private string _email;
    private string _senha;
    // ... getters e setters (Properties)
    public override string ToString()
    {
      return _nome + " " + _email;
    }
  }
}


Agora, a classe UsuarioDAO, responsavel pela persistencia de objetos do tipo Usuario.


using System.Collections.Generic;
using com.db4o;
using Db4oBrasil.Dominio;

namespace Db4oBrasil.DAO
{
  public class UsuarioDAO : DAO<Usuario>
  {
    // Checa se todos os campos obrigatórios são "não nulos"
    protected override bool ChecarRestricaoCamposNaoNulos(Usuario usr)
    {
      if(usr.Nome==null || usr.Email==null || usr.Senha==null)
        return false;
      else return true;
    }

    // Checa se o Usuario usr, se inserido no bd, violaria a restricao de     // chave primaria, no caso, o atributo email
    protected override bool ChecarRestricaoChavePrimaria(Usuario usr)
    {
      ObjectContainer db = Db4o.OpenFile(YAPFILE);
      try
      {
        Usuario proto = new Usuario();
        proto.Email = usr.Email;
        ObjectSet result = db.Get(proto);
        if (result.Count==0)
          return true;
        return false;
    }
    finally
    {
      db.Close();
    }
  }
}


O código fonte, incluindo o arquivo de solução monodevelop (.mds) e a dll do db4o 5.5 para mono, pode ser baixado aqui: Clique aqui

ps: A versão do monodevelop testada foi 0.12, usando gmcs

Dúvidas, sugestões e críticas, comentem...

[]'s
Eduardo Rocha Monteiro

Começando...

Olá, meu nome é Cássio e esse é o meu primeiro post nesse blog.
Durante algum tempo fui o representante oficial do db4o aqui no Brasil. Tendo em vista projetos pessoais que assumi, acabei declinando do cargo, mas continuo adorando e recomendando o db4o.

Para começar gostaria de fazer um comentário sobre uma dúvida que é freqüente que é encaminhada por email para mim.

Muitos querem saber se pode colocar o db4o no lugar de banco relacional x,y o z. Minha resposta é:"na maioria das vezes, não"! O objetivo do db4o é ser o repositório de objetos em situações onde o banco de dados deve ficar o mais oculto possível (não requisitar um dba), em aplicações embutidas, em aplicações standalone ou como complemento de um banco relacional.

Não pense em usar o db4o como substituto do banco relacional que você está acostumado a usar em seu ERP, CRM ou sistema de supply chain. Nessa situação ainda é melhor você manter o banco "jurassional" e para conversar com ele utilize algum framework OR/M como o NHibernate(sou c-sharpeiro, por isso recomendo o hibernate com N maiúsculo !).
Utilize o db4o nas pontas, como por exemplo aplicações que ficarão em um pda, ou ainda aplicações offline(como por exemplo, sistemas que ficam em notebooks de vendedores e no final do dia são sincronizados com o banco principal). Utilize-o ainda na linha de produção para ser o banco de dados de sistemas que controlam dispositivos.

Saber utilizar e indicar a ferramenta certa para cada situação é o que diferencia o verdadeiro profissional. Não podemos nos mover pela paixão por alguma coisa, por mais espetacular que ela seja (como o db4o) e por em risco todo um sistema crítico para uma empresa.

Abraços e contem comigo!

Cássio Rogério Eskelsen

quinta-feira, outubro 26, 2006

Nano Server

Esse é um exemplo de como se pode com poucas linhas
implementar um servidor simples para databases DB4O.
Claro que para aplicações mais sérias se deve implementar
verificações e métodos de segurança.

//JAVA

import com.db4o.Db4o;
import com.db4o.ObjectServer;

public class NanoServer {
   public static void main(String[] args) {
      ObjectServer server=Db4o.openServer("DADOS.yap",1666);
      server.grantAccess("SeuLogin","SuaSenha");
   }

}

Data Access Objects com DB4O

Implementar um sistema usando db4o eh definitivamente melhor do que usando qualquer banco relacional, usando hibernate ou não. Nao precisamos criar tabelas, configurar mapeamentos, configurar permissoes em arquivos, drivers etc...
Porem, devemos pagar um pequeno preço ao usar db4o: devemos criar as protecoes sobre violacao de campos únicos (2 produtos com mesmo codigo por exemplo), violacao de campos nao nulos, e violação de integridade ao deletar um objeto. (Também temos desvantagens em relação a falta de recursos de monitoramento e administração do banco de dados, mas discutiremos isso futuramente)
Podemos fazer isso na camada de acesso a Dados, usando o padrao DAO.
Veja como ficaria a super classe DAO (escrito em C#):

  1. Declaracao da classe: devemos criar uma classe abstrata generica.


    public abstract class DAO<T> where T: new()


  2. Metodos que fazem a checagem de restricoes de integridade devem ser sobrescritos pelo DAO de cada classe, caso contrario, simplesmente nao havera checagem:

    protected virtual bool ChecarRestricaoChavePrimaria(T t){return true;}

    protected virtual bool ChecarRestricaoCamposNaoNulos(T t){return true;}

    protected virtual bool ChecarRestricaoDeDelecao(T t){return true;}



  3. Salvando um objeto, deveremos checar se ele viola a restricao de chave primaria, e a de campos nao nulos:

    public void Salvar(T obj)
    {
       ObjectContainer db = Server.GetServer().OpenClient();
       try
       {
          if(!ChecarRestricaoChavePrimaria(obj))         throw new PKException(typeof(T).ToString());
          if(!ChecarRestricaoCamposNaoNulos(obj))
             throw new FieldNotNullException(typeof(T).ToString());
          db.Set(obj);
       }
       finally
       {
          db.Close();
       }
    }



  4. Metodo Recuperar Todos:

    public List<T> RecuperarTodos()
    {
       ObjectContainer db = Server.GetServer().OpenClient();
       List list = new List();
       try
       {
          T t = new T();
          ObjectSet result = db.Get(t);
          foreach(object item in result)
             list.Add((T)item);
       }
       finally
       {
          db.Close();
       }
          return list;
    }



  5. Metodo Excluir: Devemos tomar cuidado com este metodo. Primeiro devemos definir se devemos operar com ou sem "Cascade". Segundo, devemos checar se, de acordo com as regras de negocio, se o objeto pode ser excluido. E por ultimo, devemos ter em mente que, para excluir o objeto desejado, devemos recuperalo antes, e passalo como parametro em db.Delete() - nao basta que seja um objeto complemente identico.

    public void Excluir(T obj)
    {
       ObjectContainer db = Server.GetServer().OpenClient();
       try
       {
          if(!ChecarRestricaoDeDelecao(obj))
             throw new Exception("Violacao de restricao de integridade ao deletar objeto");
          T found = (T)db.Get(obj).Next();
          db.Delete(found);
       }
       finally
       {
          db.Close();
       }
    }


  6. Eh recomendado que cada subclasse DAO implemente o metodo recuperar por ID, que nao eh generico visto que o ID pode ser composto por um atributo, dois atributos e por ai vai.


Talvez de para melhorar isso, se alguem tiver sugestoes, serao muito bem vindas!
Em breve, uma subclasse DAO e um exemplo de uso.

[]`s
Eduardo Rocha Monteiro

sexta-feira, outubro 20, 2006

Apresentação

Apresento-me como um mero usuário de mono e db4o, formando em Ciência da Computação pela Ufes, e ingressando no Mestrado em Informática pela mesma instituição. Criei este blog, juntamente com meus colegas de universidade, Marcello e Bernard, além de Cássio Eskelsen, que já me ajudou algumas vezes com o db4o e é uma das maiores autoridades no assunto db4o no Brasil.

O principal objetivo do blog é trocar experiencias sobre o uso do db4o na fabricação de softwares de modo a buscar padrões ideais de desenvolvimento software usando banco orientado a objetos.

[]'s
Eduardo Rocha Monteiro