Insert, Update e Delete com LINQ

Em um dos projetos que estive trabalhando, precisei interagir com uma Base de Dados que possuia tabelas sem chave primária, e por motivos de compatibilidade com projetos anteriores não podia alterar as tabelas para adequar as boas práticas de desenvolvimento e inserir as chaves primárias.
No meu projeto eu precisava inserir, deletar e fazer atualizações nos registros das tabelas. Resolvi utilizar o LINQ para fazer estas operações.

O LINQ não permite a inserção, exclusão e atualização em tabelas que não possuam chave primária, por isso tive que utilizar um recurso para poder trabalhar com estas tabelas.

Criei uma base de dados com uma tabela exemplo sem chave primária, para poder demonstrar uma forma de resolver este tipo de problema. A base de dados chama-se Escola e a tabela Aluno.
Criei a classe DBML no Visual Studio que tem o seguinte formato:

AlunoDbml
Para inserir o registro de um aluno na tabela podemos utilizar o seguinte código:
        /// <summary>
        /// Executa uma instrucao Insert inserindo um aluno na
        /// base de dados.
        /// </summary>
        static void Insert()
        {
            try
            {
                EscolaClassesDataContext context = 
                    new EscolaClassesDataContext();
 
                Aluno aluno = new Aluno();
                aluno.Matricula = "67489";
                aluno.Nome = "Douglas Xavier";
                aluno.Idade = 35;
                aluno.Curso = "SQL Server";
                aluno.Endereco = "Rua Germano Souza, 675";
 
                context.Alunos.InsertOnSubmit(aluno);
                context.SubmitChanges();
 
                Console.WriteLine("Aluno inserido com sucesso!");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
Executando o método Insert() o aluno não é inserido na tabela e obtemos a seguinte mensagem de erro:
Can’t perform Create, Update or Delete Operations on Table(Aluno) because it has no primary key.
A mensagem indica que o LINQ não permite a inserção, exclusão ou atualização de registros em tabelas que não possuam chave primária.

Se testarmos o método Delete(), cujo código é exibido abaixo, obtemos a mesma mensagem de erro do método Insert():

        /// <summary>
        /// Executa uma instrucao Delete, apagando os dados de um aluno.
        /// </summary>
        static void Delete()
        {
            try
            {
                EscolaClassesDataContext context = new 
                    EscolaClassesDataContext();
 
                Aluno aluno = (from a in context.Alunos
                               where a.Idade == 22
                               select a).First();
 
                context.Alunos.DeleteOnSubmit(aluno);
                context.SubmitChanges();
                Console.WriteLine("O aluno foi apagado com sucesso!");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
Se testarmos o método Update(), cujo código é exibido abaixo, a atualização não será feita pois o método de Update do LINQ não gera exceção, por isso é muito dificil detectar qual problema está acontecendo, já que a atualização não é feita e nenhuma exceção é indicada.

        /// <summary>
        /// Executa uma instrucao Update atualizando um endereco de 
        /// um determinado aluno
        /// </summary>
        static void Update()
        {
            try
            {
                EscolaClassesDataContext context = new 
                    EscolaClassesDataContext();
 
                Aluno aluno = (from a in context.Alunos
                               where a.Nome == "Renato Borges"
                               select a).First();
                aluno.Endereco = "Av Otaviano Silva, 47";
 
                context.SubmitChanges();
                Console.WriteLine("A atualização foi realizada com" +
                    " sucesso!");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
Como resolver este problema se não podemos mexer na estrutura da tabela do banco de dados? A solução é criar uma chave primária na classe DBML. Esta chave pode ser definida em qualquer coluna. Esta definição não afeta a estrutura da tabela na base de dados, é somente um recurso para podermos trabalhar com LINQ em tabelas sem chave primária.

Para inserir uma chave primária em uma coluna da tabela Aluno, devemos alterar a propriedade PrimaryKey de False para True da coluna que servirá como chave primária.

Selecionei a coluna Matricula para servir de chave primária. Veja a figura abaixo de como ficou a definição da classe DBML.

ChavePrimaria 
Após a configuração da chave primária os métodos Insert(), Update() e Delete() podem ser executados.

Inseri o código para fazer um Select na tabela e visualizar todos os métodos sendo executados sem erros.
/// <summary>
/// Executa uma instrucao Select na base de dados.
/// </summary>
static void Select()
{
    // Cria a conexão com a base de dados Escola
    EscolaClassesDataContext context = new EscolaClassesDataContext();
 
    // Faz um SELECT na base de dados para imprimr a relação de alunos
    var queryAlunos = from a in context.Alunos
                      select a;
 
    if (queryAlunos.Count() > 0)
    {
        foreach (var item in queryAlunos)
        {
            Console.WriteLine("=========================================");
            Console.WriteLine("Matrícula: " + item.Matricula);
            Console.WriteLine("Nome: " + item.Nome);
            Console.WriteLine("Idade: " + item.Idade);
            Console.WriteLine("Curso: " + item.Curso);
            Console.WriteLine("Endereço: " + item.Endereco);
            Console.WriteLine("=======================================\r\n");
 
        }
    }
}
O código que utilizei no projeto para chamar todos os métodos foi:
        static void Main(string[] args)
        {
            Console.WriteLine("Executa o método Insert");
            Insert();
 
            Console.WriteLine("Executa o método Update");
            Update();
 
            Console.WriteLine("Executa o método Delete");
            Delete();
 
            Console.WriteLine("Executa o método Select");
            Select();
 
            Console.ReadKey();
        }
Segue a tela com o resultado dos métodos executados com sucesso:
Resultado
Os conceitos utilizados nos métodos Insert(), Update() e Delete() mostrados neste post podem ser utilizados normalmente, apenas acrescentei uma possível solução para o problema de precisar trabalhar com tabelas sem chaves primárias.