segunda-feira, 26 de janeiro de 2015

Programação orientada a objetos, mas afinal o que diabos é isso?

Hoje eu programo orientado a objetos. Pelo menos eu "acho" isso. Conheci muita gente que dizia que programava orientado a objetos mas na verdade programava de maneira procedural, orientado a evento ou RAD.

Não que as outras metodologias sejam ruins, mas é que muitas vezes elas são a ferramenta errada para se resolver  o problema. Além disso muitos programadores misturam as metodologias combinando o pior das duas em vez de o melhor das duas.

Já vi até programadores dizerem que programam orientado a objeto simplesmente porque a linguagem é orientada a objeto, ou pior ainda, porque a IDE tem "objetos" que você arrasta e solta em uma "form" e que você acessa funções (métodos) destes com seu nome e um ".".

Meu amigo, isso é RAD e não POO. Embora RAD tenha o seu valor para prototipação e aplicações rápidas e sujas, não é um bom ambiente de desenvolvimento a longo prazo. É uma programação orientada a evento degenerada. Além disso, por mais que a linguagem e o framework de uma ferramenta RAD seja orientado a objetos, a literatura e a comunidade, geralmente, não é. Eles incentivam uma forma de programação "copia/cola componentes em uma tela" onde o "programador" geralmente não sabe lhufas do que está fazendo, se é que ele programa alguma linha. Esse tipo de programa tem uma manutenibilidade quase zero.

Vide por exemplo o ambiente Delphi. É uma linguagem orientada a objeto com generics, interfaces, reflexão, sobrecarga de operadores e tudo o que uma linguagem orientada a objeto precisa ter. No entanto a comunidade Delphi é geralmente uma comunidade de "arrastadores de componentes" e "desenhistas de formulários". Não é culpa deles, a literatura disponível da ferramenta incentiva isso.

Eu mesmo fui programador Delphi durante anos e ainda é uma linguagem muito querida para mim, mas eu aprendi a fazer as coisas um pouco diferente. A sugestão que eu dou? Aprenda uma outra linguagem, C# ou Java, para expandir os seus horizontes. Se optar por C#, faça as coisas "no braço" em vez de usar as ferramentas RAD. A longo prazo elas decepcionam.

Por três vezes na minha carreira tive de fazer refactorings brutais em aplicações Delphi para possibilitar alguma expansividade em cima de um legado macarrônico, pois a manutenção era um inferno em vida.

Daí, depois de ler inúmeros artigos e livros sobre POO, DDD, padrões de projeto e outras boas práticas de código verdadeiramente OO, me cai em uma avaliação para processo seletivo o que é POO.

Eu nunca sei  qual é a resposta que os avaliadores esperam com isso porque eu nunca sei o quanto eles sabem de POO ou se eles estão equivocados. Já trabalhei em empresas onde a "crença" local era que POO era herança. Em outra os funcionários e o dono acreditavam piamente que programavam orientado a objeto, quando na verdade era programação macarrônica com método faz tudo.

A última empresa que trabalhei, um dos donos da empresa era, hummm, digamos, "programador", e ditava, ditatorialmente, as regras de como o código deveria ser desenvolvido: uma mistura de cobol não estruturado com asp, onde TODO o código do sistema estava no page_load das páginas.

Aí vem em uma avaliação a pergunta sobre o que é POO, o que é herança, o que é polimorfismo etc ... Eu devo apenas definir? Explicar? Exemplificar?

Compartilho abaixo o enunciado de uma dessas avaliações e as minhas respostas.


Conceitos teóricos

1)      Qual a importância da utilização da programação orientada a objetos? Cite algumas técnicas.

R.: A programação orientada a objetos, associada à outras boas práticas de programação, favorece um código mais coeso e menos acoplado, facilitando o reaproveitamento de código e a manutenibilidade do mesmo.Na programação orientada a objetos, dados e ações que pertencem a uma mesma entidade ou unidade lógica são agrupados em uma classe, que é um tipo de objeto.
Uma classe pode ser instanciada, ou seja, ter um objeto de seu tipo criado, e esse objeto conterá os dados da classe e as operações que atuam sobre esses dados.
A programação orientada a objeto, quando bem aplicada, permite código menor, menos repetitivo e mais eficiente, por meio da abstração.Alguns conceitos importantes em POO são herança, polimorfismo, abstração, compósição e agregação.
Herança permite que dados e comportamentos sejam transmitidos de uma classe base para uma derivada sem que código seja reescrito. Polimorfismo permite que haja diferentes implementações de um mesmo método nos diferentes objetos que implementem uma mesma interface (ou tenham um ancestral em comum).  Por exemplo, ao ter uma variável “a” da interface “i” diferente de nulo, quando executamos o método “metodo()”, o código executado será o do objeto instanciado que implemente a mesma assinatura de “metodo()”.Composição é a ligação, através de construtores ou setters, de vários objetos compondo um todo. O todo, nesse caso, é maior do que as partes e não deve existir ou funcionar sem uma de suas partes. Com composição se adiciona novos comportamentos a um objeto por adicionar mais partes que interagem entre si.Agregação é uma interação mais fraca que a composição. Objetos e coleções de objetos podem ser ligados uns aos outros criando um todo com comportamento próprio, mas as partes podem existir separadamente.
Um exemplo de composição é um Carro e suas Rodas, ou aproveitando o exemplo de e-commerce desse teste, o Pedido e seus itens. Embora os produtos podem existir sem nunca serem comprados, um Pedido não existe sem os itens, e um carro não tem propósito sem suas rodas.
Um exemplo de agregação seria um computador, pois CPU e periféricos, embora trabalhem juntos também funcionam separadamente, e o Carrinho e seus itens. Diferentemente do Pedido, um carrinho pode estar vazio, no momento do começo das compras.


  2)      Descreva os princípios SOLID e porque eles são importantes.

R.: SOLID é uma abreviação de outras 5 abreviações. Essas abreviações, em inglês são:SRP (Single responsibility principle),  significa que uma classe deve ter apenas uma responsabilidade e por consequência disso apenas um motivo para                                                                         mudar.OCP (Open/Closed principle), significa que uma classe deve ser fechada para modificação e aberta para extensão. Esse conceito é uma extensão do conceito acima e quer dizer que uma classe não deve ser modificada, mas deve ter seu comportamento extendido através de herança ou composição.
LSP (Liskov substitution principle)  é o príncípio de substituição de liskov, que significa que um objeto esperado pode ser substituido por qualquer objeto de uma classe descendente. Quando uma classe filha altera o comportamento padrão de um método ou omite uma propriedade, então o princípio de liskov está sendo violado.
ISP (Interface segregation principle) prega que de devemo separar nossos objetos em várias interfaces, e que várias interfaces que interagem e trocam mensagens entre si são melhores que um objeto único de proposito geral. Isso permite flexibilidade e reaproveitamento de código através de agregação e composição.
DIP (dependency inversion principle)  diz que um objeto não pode depender da implementação concreta de outro, mas sim de sua interface. Esse princípio nos guia, junto com o principio acima, a programar orientado a interfaces.
Por exemplo, se dois objetos executam a tarefa de enviar um e-mail de confirmação, logo deveríamos ter um terceiro, responsável pelo envio do e-mail. No entanto, se temos vários métodos ou bibliotecas de envio de e-mail e não queremos que um objeto tenha uma dependência rígida com uma implementação específica, então transformamos a classe de envio de e-mail em uma classe de serviço, extraimos sua interface e, aos objetos que necessitam de enviar um e-mail, entregamos uma variável do tipo dessa interfae, com um objeto de envio de e-mail instanciado.


 3)      Cite design patterns e para qual finalidade eles existem.

R.:  São padrões de projeto. Um conjunto de abstrações encontradas em vários projetos que se repetem, pois visam reslver problemas específicos.
No livro “Padrões de Projeto”, do grupo “Gang of Four”, existe um catálogo de padrões de projeto identificados  e descritos por ele, como exemplos. Mas este livro não é a única fonte. Há também o livro “Patterns of Enterprise Application Development” de Martin Fowler.
Dentre os padrões de projeto podemos citar os criacionais factory method, que é um método que instancia um objeto inicializando-o e devolve-o para o chamador, abstract factory, que é uma classe abstrata com factory methods que, valendo-se de polimorfismo, delega a criação de objetos concretos à suas própria implementações concretas, singleton, que cria uma instância de um objeto e permite que apenas um seja criado. Podemos citar também o padrão strategy, que permite que uma dentre várias ações diferentes possam ser escolhidas dependendo do objeto instanciado e o padrão iterator, usado para se navegar em uma coleção de objetos.Escrevi 4 artigos para a revista Clube Delphi sobre padrões de projeto, 3 sobre factory method e abstract factory e um sobre singleton, seguem links abaixo: http://www.devmedia.com.br/websys.4/webreader.asp?cat=3&revista=clubedelphi_122#a-2883http://www.devmedia.com.br/websys.4/webreader.asp?cat=3&revista=clubedelphi_123#a-2969http://www.devmedia.com.br/websys.4/webreader.asp?cat=3&revista=clubedelphi_124#a-3081http://www.devmedia.com.br/websys.4/webreader.asp?cat=3&revista=clubedelphi_133#a-3902 Design patterns não significam “Normas” de projeto, e sim “padrões” de projeto. Padrões aqui no sentido matemático: uma forma que se repete.

  4)       Quais os principais conceitos que compõe o DDD.

R.: O principal conceito do DDD é o domínio, ou seja, as regras de negócio. O foco do DDD é no domínio e as classes da camada de negócio devem ser o core do sistema.
Como apoio a essa técnica DDD preconiza que o time de desenvolvimento deve adotar o vocabulário, termo se jargões próprios do domínio e criar um vocabulário padrão para toda a equipe.
DDD desencoraja um desenvolvimento em um número muit o grande de camadas (por exemplo usando WCF entre a camada de aplicação e a GUI) porque o uso de DTO’s  não é natural à DDD. Nessa metodologia, tudo que foge ao negócio como glue code e plumbing code, é considerado parte da infraestrutura. A esse conceito dá-se o nome de linguagem ubíqua.
Outros conceitos importantes em DDD é o conceito de Entidade (objetos com ID e ciclo de vida, que são persistidos e têm existência por si só) e sua distinção de objetos de valor (simples contêineres para valores sem ciclo de vida ou identidade própria).  Também são conceitos da DDD agregados, serviços e repositórios.DDD também é associado à outras boas práticas como TDD e a separação do sistema em 4 camadas: Interface de usuário, Aplicação, Dominio (entidades e objetos de valor ficam aqui) e Infra-estrutura (repositórios, serviços e outras classes de apoio).


Será que me estendi demais? Tenho esse costume, e tenho o costume de fugir do assunto também, parece que minha mente não funciona muito linearmente, tampouco objetivamente. No entanto, o que você escreveria de memória, sem consultar seus livros anotações revistas e sites?

Lista ligada em C#

Um dos assuntos que estudamos em ciência da computação ou processamento de dados que eu mais gosto é: Algoritmos e Estrutura de Dados.

Se bem que gostar não é garantia de dominar, né? É sempre um assunto meio complicado. Admiro muito os professores dessa  matéria, que resolvem problemas desse tipo quase sem pensar.

Uma das coisas que se estuda nessa matéria é a Lista Ligada.  Trata-se de uma estrutura simples, porém poderosa, onde um atributo desta estrutura é um dado (de qualquer tipo que o programador queira) e um ponteiro para um próximo objeto de mesmo tipo. Se o ponteiro for null (em linguagens c-like, nil em pascal, nothing em basic) significa que não há próximo objeto.

Abaixo a figura de um nó da lista.


Esses nós podem ser ligados uns aos outros em cadeias, conforme a figura abaixo.


Além disso as listas podem ter dois ponteiros, um apontando para o elemento posterior e outro apontando para o anterior, formando uma lista duplamente ligada. A lista pode também ser circular, com o último elemento apontando para o primeiro. Nesses casos é comum termos um valor especial no "primeiro" nó para indicar que ele é a "cabeça" e assim não se navegar infinitamente pela lista. A cabeça também pode ser implementada com um ponteiro fora da lista circular apontando para um elemento qualquer da lista, sendo este o primeiro.

Em linguagens sem suporte a OO isso é feito criando - se uma struct (ou record) onde um dos elementos é o tipo de dado requerido e o outro é um ponteiro para a própria estrutura.  Nas linguagens OO todo objeto já é um ponteiro, a manipulação de referências torna-se transparente. Um nó nada mais é do que um objeto contendo uma propriedade de um determinado tipo e a outra propriedade do próprio tipo nó.

Embora seja uma estrutura muito útil, se você trabalha com sistemas de informação você raramente usará listas ligadas no seu dia-a-dia, porque os frameworks e bibliotecas que usamos no nosso trabalho já tem tudo isso pronto, por isso podemos focar em regras de negócio e usabilidade, que é o que realmente é importante especificamente em nossa área.

No entanto, periodicamente, aparecem problemas e exercícios envolvendo listas ligadas em avaliações de processos seletivos.

Um processo seletivo pelo qual eu passei recentemente tinha a seguinte avaliação:

Exercício A - implementação de lista ligada
Os objetivos desse exercício são:
  • Parte 1 - implementar um sistema de lista-ligada
  • Parte 2 - realizar uma tarefa simples usando essa implementação
Parte 1 - implementação da lista ligada
Implemente um sistema de lista ligada integralmente de sua autoria. Não use as classes de
Listas das suas bibliotecas
Você decide se a solução vai envolver (uma ou mais) classes ou apenas funções; a
implementação deve ser adequada (não excessiva) para a utilização que se fa rá dela (vide
abaixo).

Parte 2 - utilização da lista ligada
Utilizando o sistema de lista ligada implementado na etapa anterior, escreva um programa que:
  • crie duas listas ligadas: (por ex) Lista1 e Lista2
  • leia o arquivo texto entrada.txt e armazene suas linhas em Lista1
  • copie os elementos de Lista1 para Lista2 invertendo a sua ordem
  • grave os elementos de Lista2 no arquivo texto saida.txt

Nada muito difícil, como pode ser visto, mas é o tipo de coisa que pode te pegar de surpresa porque você só viu na faculdade e, francamente, poucos de nós treinamos este tipo de algoritmo para estarmos sempre preparados.

Minha resolução foi a seguinte: primeiro criei o nó.

    /// 
    /// Classe Nó, um elemento da lista. Optei por torná-la genérica, assim ela pode carregar qualquer elemento em um nó.
    /// 
    /// 
    public class No
    {
        public T valor { get; set; }
        public No proximo { get; set; }
    }

Note que criei a estrutura genérica assim um nó pode armazenar qualquer tipo de dado e tem uma propriedade, da classe No, que é o próximo nó genérico do mesmo tipo.
Depois criei a função para ler o arquivo de entrada, conforme o código abaixo. Estas funções para manipulação da lista são métodos estáticos na própria classe Program de um console application que fiz.


        /// 
        /// Carrega o arquivo definido no caminho e cria uma lista ligada na variavel n
        /// 
        /// 
        /// 
        private static void CarregaArquivo(No n, string caminho)
        {
            using (StreamReader sr = new StreamReader(caminho))
            {
                No p = n;
                string s = sr.ReadLine();
                p.valor = s;
                while (!sr.EndOfStream)
                {
                    p.proximo = new No();
                    s = sr.ReadLine();                    
                    p = p.proximo;
                    p.valor = s;
                }
            }
        }
Fiz um código estilo quick and dirty, obviamente esse código poderia ser otimizado. Ele poderia trazer a lista no seu retorno, atuando como factory method, assim eu não precisaria passar uma variável para ele inicializar por mim. Mas ele funciona. Ele pega a primeira linha do aquivo, joga no primeiro elemento e encadeia novos elementos conforme vai lendo as próximas linhas. Acredito não ser necessário explicar cada linha de código aqui, o .net framework fala por si :).

Uma das coisas que o avaliador quer saber nesse tipo de exercício é se o candidato sabe recursividade. E para entender a recursividade você primeiro precisa saber a recursividade. Funções que se chamam a si mesmas, conceitos definidos em termos de si mesmos. Isso é recursividade. Você a vê a rodo na natureza e na matemática.
Por isso as funções Imprime e Inverte eu criei recursiva. Na verdade é a melhor maneira de se trabalhar com estruturas de dados.
Criei também uma Inverte iterativa (usando o laço while) porque me deparei com um desafio desses em uma outra avaliação para processo seletivo: Inverta uma lista ligada sem usar recursividade. Parece que o pessoal conhece "de cor" só a maneira recursiva. No dia achei difícil, estava nervoso, começo de carreira, e fui pego de surpresa. Hoje parece trivial.


        /// 
        /// imprime o conteudo da lista ligada (partindo do nó n) na tela. Faz isso recursivamente. 
        /// 
        /// 
        private static void Imprime(No n)
        {
            if (n == null)
                return;

            Console.WriteLine(n.valor);

            n = n.proximo;

            Imprime(n);
        }


        /// 
        /// Inverte usando while
        /// 
        /// 
        /// 
        private static No InverteIterativa(No n)
        {
            No tmp;
            No corrente = n;
            No invertido = null;
            while (corrente != null)
            {
                tmp = corrente.proximo;
                corrente.proximo = invertido;
                invertido = corrente;
                corrente = tmp;
            }
            return invertido;
        }

        /// 
        /// inverte recursivamente
        /// 
        /// 
        /// 
        private static void InverteRecursiva(No n, ref No invertida)
        {
            No tmp;
            No corrente = n;
            if (n == null)
                return;
            tmp = corrente.proximo;
            corrente.proximo = invertida;
            invertida = corrente;
            corrente = tmp;
            InverteRecursiva(corrente, ref invertida);
        }

        /// 
        /// salva a lista resultante no caminho especificado
        /// 
        /// 
        /// 
        private static void Salva(No n, string caminho)
        {
            using (StreamWriter sw = new StreamWriter(caminho))
            {
                No corrente = n;
                while (corrente != null)
                {
                    sw.WriteLine(corrente.valor);
                    corrente = corrente.proximo;
                }
            }
        }
E a função main é esta:


        static void Main(string[] args)
        {
            No L1 = null;
            No L2 = null;

            L1 = new No();
            CarregaArquivo(L1, @"c:\entrada.txt");
            Console.WriteLine("Dados originais");
            Imprime(L1);
            L2 = InverteIterativa(L1);
            //InverteRecursiva(L1, ref L2);
            Console.WriteLine("Dados invertidos");
            Imprime(L2);
            Salva(L2, @"c:\saida.txt");
            Console.ReadLine();
         
        }

Então é isso. Você pode baixar aqui o código completo desse exercício de lista ligada. Espero que te ajude nos seus estudos e nas suas entrevistas. Me deixe saber se tem algo errado com o código (sempre tem).

Uma versão alternativa da função de carregar arquivo seria assim:


        private static No CarregaAlternativo(string caminho)
        {
            No result = new No();
            No next = result;
            using (StreamReader sr = new StreamReader(caminho))
            {
                string s = "";
                while ((s = sr.ReadLine())!=null)
                {                    
                    next.valor = s;
                    if (!sr.EndOfStream)
                    {
                        next.proximo = new No();
                        next = next.proximo;
                    }
                }
            }

            return result;
        }


Have fun :)

domingo, 25 de janeiro de 2015

Função para criar nova data em SQL

O SQL 2012 e superior tem a função DATEFROMPARTS para criar uma nova data a partir dos inteiros Ano, Mes e Dia, mas as versões 2000, 2005 e 2008 como é que fica?

Fica assim: você mesmo faz a função.



SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- ############################################################################################################################################
-- # NOME   : DATEFROMPARTS
-- # PRODUTO  : SQL Server
-- # DEVELOPER  : Vitor Luiz Rubio
-- # COPYRIGHT  : 
-- # OBJETIVO  : Gerar uma data a partir dos seus componentes inteiros
-- # VERSAO   : 1.0
-- # DT. CRIACAO : 2013-04-18
-- # DT. ALTERACAO : 
-- #
-- # DEPENDENCIAS :
-- # 
-- # DEPENDENTES :
-- #
-- # HISTÓRICO
-- # 2013-04-18 : Criação
-- #  
-- ############################################################################################################################################ 

CREATE FUNCTION DATEFROMPARTS
(
 @Year int,
 @Month int,
 @Day int
)
RETURNS datetime
AS
BEGIN
 --data 0 é 1/1/1900
 
 set @Year = @Year - 1900;
 set @Month = @Month - 1;
 set @Day = @Day - 1;

 return dateadd(day, @Day, dateadd(month, @Month, dateadd(year, @Year, 0)))
 
 --teste
 --select dbo.DATEFROMPARTS(2013, 4, 18)
 --select dbo.DATEFROMPARTS(2014, 1, 1)
 --select dbo.DATEFROMPARTS(1983, 2, 14)
 
END
GO



sábado, 24 de janeiro de 2015

Duas maneiras de listar as chaves estrangeiras de um banco de dados

AS vezes precisamos listar todas as chaves estrangeiras de um banco de dados (e as tabelas/campos referenciados pelas mesmas). Tanto para automação de nosso mecanismo de persistência como para documentação do banco de dados.

Em algumas operações nós precisamos excluir todas as constraints, para fazer alguma manutenção ou inclusão desconsiderando-se a integridade referencial (geralmente ao passar dados de um banco para outro, cargas, restaurações etc), sendo estas recriadas depois.

A consulta pelas chaves estrangeiras pode ser feita usando-se as tabelas de sistema sysobjects e syscolumns ou as views de sistema INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS e INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE.

Usando sysobjects  e syscolumns

SELECT 
 o3.name 'Nome_Chave_Estrangeira', 
 o2.name 'Tabela',
 sc1.name 'Coluna (FK)',
 
 o1.name 'Tabela Referenciada',
 sc2.name 'Coluna Referenciada (PK)'foreign key ('+sc1.name+') references '+o1.name+'('+sc2.name+')'  
FROM 
 sysforeignkeys fk 
 INNER JOIN sysobjects o1 on o1.id = fk.rkeyid --para obter a cahve estrangeira e a tabela referenciada
 INNER JOIN sysobjects o2 on o2.id = fk.fkeyid --tabla de objetos e campo da chave pk
 inner join sysobjects o3 on o3.id = fk.constid --tabela de objetos e campo da constraint (constid) para pegar o  nome da constraint
 inner join syscolumns sc1 on sc1.id = fk.fkeyid and sc1.colid = fk.fkey  --coluna pk
 inner join syscolumns sc2 on sc2.id = fk.rkeyid and sc2.colid = fk.rkey  --coluna referenciada fk
where 
 o1.name = 'company'

Usando views de sistema.


SELECT
    rc.CONSTRAINT_NAME 'Nome_Chave_Estrangeira',     
    rcu.TABLE_NAME 'Tabela', 
    rcu.COLUMN_NAME 'Coluna (FK)',
    rcu1.TABLE_NAME 'Tabela Referenciada',
    rcu1.COLUMN_NAME 'Coluna Referenciada (PK)'
FROM
    INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
INNER JOIN 
    INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE rcu 
      ON rc.CONSTRAINT_CATALOG = rcu.CONSTRAINT_CATALOG 
         AND rc.CONSTRAINT_NAME = rcu.CONSTRAINT_NAME
INNER JOIN 
    INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE rcu1 
      ON rc.UNIQUE_CONSTRAINT_CATALOG = rcu1.CONSTRAINT_CATALOG 
         AND rc.UNIQUE_CONSTRAINT_NAME = rcu1.CONSTRAINT_NAME

where rcu1.TABLE_NAME = 'company'

Podemos notar que usando as views de sistema nosso filtro é mais simples, mas usando sysobjects e syscolumns  temos mais flexibilidade no que queremos trazer.

Você pode fazer uma consulta gerar, como string/varchar, o código necessário para exclui todas as suas constraints, caso existam, e recriar todas elas, caso não existam, mas atenção: se alguma das suas constraints tiver políticas diferentes quanto ao "on update cascade" ou "on delete cascade" você simplesmente não pode excluí-las e recriá-las assim, em massa.

SELECT 
 o3.name 'Nome_Chave_Estrangeira', 
 o2.name 'Tabela',
 sc1.name 'Coluna (FK)',
 
 o1.name 'Tabela Referenciada',
 sc2.name 'Coluna Referenciada (PK)',
 
 
 'IF  EXISTS (SELECT * FROM sysobjects WHERE id = OBJECT_ID(N'''+o3.name+''') AND parent_obj = OBJECT_ID(N'''+o2.name+''')) ALTER TABLE '+o2.name+' DROP CONSTRAINT ['+o3.name+']',
 'IF  not EXISTS (SELECT * FROM sysobjects WHERE id = OBJECT_ID(N'''+o3.name+''') AND parent_obj = OBJECT_ID(N'''+o2.name+''')) ALTER TABLE '+o2.name+' add CONSTRAINT ['+o3.name+'] foreign key ('+sc1.name+') references '+o1.name+'('+sc2.name+')'  
FROM 
 sysforeignkeys fk 
 INNER JOIN sysobjects o1 on o1.id = fk.rkeyid --para obter a cahve estrangeira e a tabela referenciada
 INNER JOIN sysobjects o2 on o2.id = fk.fkeyid --tabla de objetos e campo da chave pk
 inner join sysobjects o3 on o3.id = fk.constid --tabela de objetos e campo da constraint (constid) para pegar o  nome da constraint
 inner join syscolumns sc1 on sc1.id = fk.fkeyid and sc1.colid = fk.fkey  --coluna pk
 inner join syscolumns sc2 on sc2.id = fk.rkeyid and sc2.colid = fk.rkey  --coluna referenciada fk
where 
 o1.name = 'company'


Esse link foi de grande ajuda para identificar todas as chaves estrangeiras de uma tabela

Have Fun :)

Postagens populares

Marcadores

delphi (60) C# (31) poo (21) Lazarus (19) Site aos Pedaços (15) sql (13) Reflexões (10) .Net (9) Humor (9) javascript (9) ASp.Net (8) api (8) Básico (6) Programação (6) ms sql server (5) Web (4) banco de dados (4) HTML (3) PHP (3) Python (3) design patterns (3) jQuery (3) livros (3) metaprogramação (3) Ajax (2) Debug (2) Dicas Básicas Windows (2) Pascal (2) games (2) linguagem (2) música (2) singleton (2) tecnologia (2) Anime (1) Api do Windows (1) Assembly (1) Eventos (1) Experts (1) GNU (1) Inglês (1) JSON (1) SO (1) datas (1) developers (1) dicas (1) easter egg (1) firebird (1) interfaces (1) introspecção (1) memo (1) oracle (1) reflexão (1)