ATUALIZAÇÃO: recebi alguns votos positivos sobre isso ultimamente, então achei que deixaria as pessoas saberem que os conselhos que dou abaixo não são os melhores. Desde que comecei a mexer no Entity Framework em bancos de dados sem chave antigos, percebi que a melhor coisa que você pode fazer BY FAR é fazê-lo revertendo o código primeiro. Existem alguns bons artigos por aí sobre como fazer isso. Basta segui-los e, quando desejar adicionar uma chave, use anotações de dados para "falsificar" a chave.
Por exemplo, digamos que eu saiba que minha mesa Orders
, embora não tenha uma chave primária, garante apenas um número de pedido por cliente. Como essas são as duas primeiras colunas da tabela, eu configuraria o código das primeiras classes para ficar assim:
[Key, Column(Order = 0)]
public Int32? OrderNumber { get; set; }
[Key, Column(Order = 1)]
public String Customer { get; set; }
Ao fazer isso, você basicamente finge que a EF acredita que há uma chave de cluster composta por OrderNumber e Customer. Isso permitirá que você faça inserções, atualizações, etc. na sua mesa sem chave.
Se você não está muito familiarizado com a reversão do Code First, encontre um bom tutorial sobre o Entity Framework Code First. Em seguida, encontre um no Reverse Code First (que está executando o Code First com um banco de dados existente). Depois, volte aqui e olhe para os meus principais conselhos novamente. :)
Resposta original :
Primeiro: como já foi dito, a melhor opção é adicionar uma chave primária à tabela. Ponto final. Se você puder fazer isso, não leia mais.
Mas se você não pode, ou simplesmente se odeia, há uma maneira de fazer isso sem a chave primária.
No meu caso, eu estava trabalhando com um sistema legado (originalmente arquivos simples em um AS400 portado para o Access e, em seguida, portado para o T-SQL). Então eu tive que encontrar uma maneira. Esta é a minha solução. O seguinte funcionou para mim usando o Entity Framework 6.0 (o mais recente no NuGet até o momento desta redação).
Clique com o botão direito do mouse no seu arquivo .edmx no Gerenciador de Soluções. Escolha "Abrir com ..." e selecione "Editor de XML (texto)". Vamos editar manualmente o código gerado automaticamente aqui.
Procure uma linha como esta:
<EntitySet Name="table_name" EntityType="MyModel.Store.table_name" store:Type="Tables" store:Schema="dbo" store:Name="table_nane">
Retire store:Name="table_name"
do final.
Mude store:Schema="whatever"
paraSchema="whatever"
Olhe abaixo dessa linha e encontre a <DefiningQuery>
tag. Ele terá uma grande e velha declaração de seleção. Remova a tag e seu conteúdo.
Agora sua linha deve ficar assim:
<EntitySet Name="table_name" EntityType="MyModel.Store.table_name" store:Type="Tables" Schema="dbo" />
Temos mais alguma coisa para mudar. Acesse seu arquivo e encontre o seguinte:
<EntityType Name="table_name">
Nas proximidades, você provavelmente verá um texto comentado avisando que ela não possui uma chave primária identificada; portanto, a chave foi inferida e a definição é uma tabela / exibição somente leitura. Você pode deixá-lo ou excluí-lo. Eu deletei.
Abaixo está a <Key>
tag. É isso que o Entity Framework usará para inserir / atualizar / excluir. ASSIM TENHA CERTEZA DE FAZER ISSO DIREITO. A propriedade (ou propriedades) nessa tag precisa indicar uma linha identificável exclusivamente. Por exemplo, digamos que eu saiba que minha mesa orders
, embora não tenha uma chave primária, garante apenas um número de pedido por cliente.
Então o meu se parece com:
<EntityType Name="table_name">
<Key>
<PropertyRef Name="order_numbers" />
<PropertyRef Name="customer_name" />
</Key>
Sério, não faça isso errado. Digamos que, embora nunca deva haver duplicatas, de alguma forma duas linhas entram no meu sistema com o mesmo número de pedido e nome do cliente. Opa! É isso que recebo por não usar uma chave! Então, eu uso o Entity Framework para excluir um. Como sei que a duplicata é a única ordem feita hoje, faço o seguinte:
var duplicateOrder = myModel.orders.First(x => x.order_date == DateTime.Today);
myModel.orders.Remove(duplicateOrder);
Adivinha? Acabei de excluir a duplicata e o original! Isso porque eu disse ao Entity Framework que order_number / cutomer_name era minha chave primária. Então, quando eu disse para remover duplicateOrder, o que ele fez em segundo plano foi algo como:
DELETE FROM orders
WHERE order_number = (duplicateOrder's order number)
AND customer_name = (duplicateOrder's customer name)
E com esse aviso ... agora você deve ir!