Pergunta

Uma coisa que achei continuamente muito confusa em usar um banco de dados de objetos como db4o é como você deve lidar com migrações complexas que normalmente seriam tratadas pelo SQL/PL-SQL.

Por exemplo, imagine que você tinha uma tabela em um banco de dados relacional chamado my_users. Originalmente, você tinha uma coluna chamada "Full_Name", agora que seu software está no V2 que você deseja remover esta coluna, dividir os nomes completos em um espaço em branco e colocar a primeira parte em uma coluna chamada "First_name" e a segunda em uma coluna nomeado last_name. No SQL, eu simplesmente povoaria as colunas "First_Name" e "Second_Name", removendo a coluna original chamada "Full_Name".

Como eu faria isso em algo como DB4O? Escrevo um programa Java que os scripts que procuram todos os objetos do user.class, configurando Full_Name como NULL enquanto configura o First_Name e o Last_Name? Quando eu faço meu próximo comprometimento do SVN, não haverá propriedade de campo/feijão correspondente a Full_Name, isso seria um problema? Parece que usá -lo em um aplicativo de produção em que minhas mudanças "esquema", eu gostaria de escrever um script para migrar dados da versão x para a versão x+1 e depois na versão x+2 remover as propriedades que estou tentando Livre -se da versão x+1, pois não posso escrever um script Java para modificar propriedades que não fazem mais parte do meu tipo.

Parece que parte do problema é que um RDBMS resolve a que objeto você está se referindo com base em um nome simples baseado em string de caso, em um idioma como a digitação Java é mais complicada do que isso, você não pode se referir a uma propriedade se o getter /Setter/Field não é um membro da classe carregado no tempo de execução, portanto você precisa ter 2 versões do seu código no mesmo script (hmm, carregadores de classe personalizados soam como uma dor), que a nova versão da sua classe pertence a pertencer a Outro pacote (parece confuso), ou use a versão x+1 x+2 que mencionei (requer muito mais planejamento). Talvez haja alguma solução óbvia que eu nunca obtenha nos documentos do DB4O.

Alguma ideia? Espero que isso faça algum sentido.

Foi útil?

Solução

Primeiro, o DB4O lida com o 'simples' cenários como adicionar ou remover um campo automaticamente. Ao adicionar o campo, todo o objeto existente tem o valor padrão armazenado. Quando você remove um campo, os dados do objeto existente ainda estão no banco de dados e você ainda pode acessá -lo. Renomear campo Especial 'refatoramento'.

Agora seu cenário você faria algo assim:

  1. Remova o campo 'Full_name', adicione os novos campos 'First_Name' e 'Second_Name'
  2. Itera sobre todos os objetos de 'endereço'
  3. Acesse o campo antigo via 'StoredClass'-Api
  4. Divida, altere, atualize etc. o valor. Defina os novos valores no novo campo e armazene o objeto.

Vamos supor que tenhamos um 'endereço'. O campo 'Full_name' foi removido. Agora não vamos copiá -lo para o 'primeiro nome' e o 'sobrenome'. Então poderia ser assim (java):

    ObjectSet<Address> addresses = db.query(Address.class);
    StoredField metaInfoOfField = db.ext().storedClass(Address.class).storedField("full_name", String.class);
    for (Address address : addresses) {
        String fullName = (String)metaInfoOfField.get(address);
        String[] splitName = fullName.split(" ");
        address.setFirstname(splitName[0]);
        address.setSurname(splitName[1]);
        db.store(address);
    }

Como você sugeriu, você escreveria o código de migração para cada versão da versão. Um campo não faz mais parte da sua classe, você deve acessá-la com 'Storedfield' Api como acima.

Você pode obter uma lista de todas as aulas 'armazenadas' com ObjectContainer.ext().storedClasses(). Com StoredClass.getStoredFields() Você pode obter uma lista de todos os campos da loja, não é mais que o campo não existe mais em sua classe. Se uma classe não existir mais, você ainda poderá obter os objetos e acessá-lo por meio da classe 'GenericObject'.

ATUALIZAÇÃO: Para cenários mais complexos, onde um banco de dados precisa migrar sobre etapas de várias versões.

Por exemplo, na versão v3, o objeto de endereço parece completamente diferente. Portanto, o 'Migration-Script' para V1 a V2 não tem mais os campos que exige (primeiro nome e Surename no meu exemplo). Eu acho que existem várias possibilidades para lidar com isso.

  1. (Assumindo Java para essa idéia. Certamente há um equivalente no .NET). Você poderia fazer a etapa de migração um Groovy-Script. Portanto, cada um que cada script não interfere com outro. Em seguida, você define 'classes' as classes necessárias para a migração lá. Portanto, cada migração tem suas próprias classes de migração. Com apelido Você ligaria suas classes de migração Groovy às classes Java reais.
  2. Criando classes de refatoramento para cenários complexos. Também liga essas classes com apelido.

Outras dicas

Estou tirando um tiro selvagem aqui, porque não refatori muitos dados em minha vida.

Você está fazendo uma comparação estranha: se você quisesse 'migrar' o banco de dados, provavelmente teria que fazer o x+1, x+2 Abordagem de versão que você descreveu, mas eu realmente não sei - eu não saberia como fazer isso com o SQL, já que não sou um especialista em banco de dados.

Se você estiver migrando 'frio', no entanto, você pode fazê -lo em um passo instanciando um novo objeto dos dados antigos, armazenar o novo objeto, excluir o objeto antigo para cada objeto na loja. Ver referência db4o.

Mas, honestamente: o mesmo processo em um RDBMS também é complicado, porque você terá que desativar verificações de restrição (e possivelmente gatilhos, etc.) para realmente executar a operação - talvez não no exemplo que você forneceu, mas para a maioria real -casos mundos. Afinal, a divisão da corda é tão fácil que haverá pouco ganho.

No SQL, eu simplesmente povoaria as colunas "First_Name" e "Second_Name"

Sim, com um simples operação de divisão de string, você pode simplesmente faça isso. Mas, em um cenário típico de refatoração, você está reestruturação de objetos com base em conjuntos grandes e complicados de regras que podem não ser facilmente expressos no SQL, pode precisar de cálculo complexo ou fontes de dados externas.

Para fazer isso, você também teria que escrever código.

Afinal, não vejo muita diferença nos dois processos. Você sempre terá que ter cuidado com dados ao vivo e certamente fará um backup nos dois casos. A refatoração é divertida, mas a persistência é complicada, portanto, sincronizá -la é um desafio em qualquer caso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top