sábado, 24 de outubro de 2009

Mudar PartitionKey e RowKey? "NÃO", diz o Azure SDK

Table Storage do Azure. Criamos uma classe "Usuario", pra ser armazenada "lá" (na(s) nuvem(ns)). Baseando o código num dos exemplos que encontramos por aí, tudo rodou ok.

"Beleza", digo eu. "Vamos codificar na vera agora". Bem, estávamos usando o identificador da empresa como Partition Key, e o e-mail do usuário como Row Key. Só que meu código estava meio torto. Por exemplo, pra acessar o e-mail do usuário a gente escrevia

string email = Usuario.RowKey; // Usuario.RowKey???

Pra acessar a empresa:

int codigoEmpresa = Usuario.PartitionKey; // Hã?

Obviamente, quero usar Usuario.EMail e Usuario.CodigoEmpresa. Aí começou meu quebra-pau com o Azure.

Quando a gente cria uma classe que representa as entidades (= linhas) de uma tabela (= tabela) no Table Storage do Azure, esta classe tem que ser marcada com o atributo DataServiceKeys. No exemplo de código que pegamos, a classe estava marcada com

[DataServiceKeys("PartitionKey", "RowKey"]
public class Usuario
{
int PartitionKey { get; set; }
string RowKey { get; set; }
//... Resto do código
}

"Simples", penso eu. "É só especificar o nome das propriedades que serão as Partition e Row Keys naquele atributo". Rá. Ledo engano. (Não sei o que é "ledo", mas sempre que você está totalmente enganado, o engano é um "ledo engano"). Mudei o nome das propriedades PartitionKey e RowKey para CodigoEmpresa e EMail. Renomeei as propriedades no código. Recompilei. Tudo ok.

[DataServiceKeys("CodigoEmpresa ", "EMail "]
public class Usuario{
int CodigoEmpresa { get; set; }
string EMail { get; set; }
//... Resto do código
}

Aí fui rodar o DevTableGen para gerar as tabelas no Development Storage. A tabela de usuários não foi gerada.

Peculiaridade nº 1: Se o atributo DataServiceKeys não recebe literalmente as strings "PartitionKey" e "RowKey" como parâmetro, o DevTableGen não gera a tabela.

"OME", digo eu. "Oh My Egg". Vamos então manter as propriedades PartitionKey e RowKey na minha classe, mas vamos pelo menos criar propriedades que fazem mais sentido:
[DataServiceKeys("PartitionKey", "RowKey"]
public class Usuario{
int PartitionKey { get; set; } // aqui vai ficar o código da empresa
string RowKey { get; set; } // aqui vai ficar o e-mail do usuário
// Por aqui eu leio o código da empresa
int CodigoEmpresa {
get { return PartitionKey; }
}
// Por aqui eu leio o e-mail do usuário
string EMail {
get { return RowKey; }
}
//... Resto do código
}

Coloquei propriedades read-only somente para poder dar acesso às informações que estão em PartitionKey e RowKey, mas com nomes que fazem mais sentido para a minha classe ("mais de acordo com o domínio do problema", como diriam os cientificamente corretos). Só que o DevTableGen não gerou a tabela Usuario, pois (peculiaridade nº 2) ele se recusa a gerar a tabela se há propriedades read-only na classe.

"OMLE", pensei. "Oh My Left Egg". Já cansado desta discussão e sem pensar direito, coloquei então o set das propriedades CodigoEmpresa e EMail:

[DataServiceKeys("PartitionKey", "RowKey"]
public class Usuario
{
int PartitionKey { get; set; } // aqui vai ficar o código da empresa
string RowKey { get; set; } // aqui vai ficar o e-mail do usuário
// Por aqui eu leio o código da empresa
int CodigoEmpresa {
get { return PartitionKey; }
set { PartitionKey = value; }
}
// Por aqui eu leio o e-mail do usuário
string EMail {
get { return RowKey; }
set { RowKey = value; }
}
//... Resto do código
}

A consequência (óbvia, por sinal) é que o DevTableGen gerou a tabela com ambos os pares de propriedades: agora eu tinha uma tabela de usuários que guardava o código da empresa em PartitionKey e CodigoEmpresa, e o e-mail em RowKey e EMail. Não interessa para ele se a propriedade é só uma "acessora" (accessor) a valores armazenados em outro lugar; a propriedade existe, então ele gera uma coluna pra ela.

Ainda fiz mais algumas tentativas, mas no final das contas acabei com a classe Usuario guardando o código da empresa em PartitionKey e o e-mail do usuário em RowKey, e acrescentando outra sugestão no Connect, pra ver se a Microsoft dá um jeito nisto.

A resposta foi "Obrigado por reportar esta situação. Vamos mandar para o time e blablabla vão ver se implementam para a próxima versão". Hum. Quero só ver...