Pergunta

Por várias razões que eu não tenho a liberdade para falar, estamos definindo uma visão em nosso banco de dados SQL Server 2005 como assim:

CREATE VIEW [dbo].[MeterProvingStatisticsPoint]
AS
SELECT
    CAST(0 AS BIGINT) AS 'RowNumber',
    CAST(0 AS BIGINT) AS 'ProverTicketId',
    CAST(0 AS INT) AS 'ReportNumber',
    GETDATE() AS 'CompletedDateTime',
    CAST(1.1 AS float) AS 'MeterFactor',
    CAST(1.1 AS float) AS 'Density',
    CAST(1.1 AS float) AS 'FlowRate',
    CAST(1.1 AS float) AS 'Average',
    CAST(1.1 AS float) AS 'StandardDeviation',
    CAST(1.1 AS float) AS 'MeanPlus2XStandardDeviation',
    CAST(1.1 AS float) AS 'MeanMinus2XStandardDeviation'
WHERE 0 = 1

A idéia é que o Entity Framework irá criar uma entidade com base nesta consulta, o que ele faz, mas ele gera-lo com um erro que afirma o seguinte:

Aviso 6002: A tabela / view 'Keystone_Local.dbo.MeterProvingStatisticsPoint' não tem uma chave primária definida. A chave tem sido inferido ea definição foi criado como um read-only table / view.

E decide que o campo CompletedDateTime será esta chave principal entidade.

Estamos usando EdmGen para gerar o modelo. Existe uma maneira para não ter a estrutura de entidade incluem qualquer campo dessa visão como uma chave primária?

Foi útil?

Solução

Nós tivemos o mesmo problema e esta é a solução:

Para forçar estrutura de entidade para usar uma coluna como uma chave primária, uso ISNULL.

Para estrutura de entidade força para não usar uma coluna como uma chave primária, uso NULLIF.

Uma maneira fácil de aplicar esta é envolver a instrução SELECT de seu ponto de vista em outra seleção.

Exemplo:

SELECT
  ISNULL(MyPrimaryID,-999) MyPrimaryID,
  NULLIF(AnotherProperty,'') AnotherProperty
  FROM ( ... ) AS temp

Outras dicas

Eu era capaz de resolver isso usando o designer.

  1. Abra o Model Browser.
  2. Encontre o ponto de vista no diagrama.
  3. Botão direito do mouse na chave primária, e certifique-se "Entidade Key" está marcada.
  4. Multi-selecionar todas as chaves não primárias. Use as teclas Ctrl ou Shift.
  5. Na janela Propriedades (pressione F4 se necessário para vê-lo), altere o "Entidade Key" drop-down para Falso.
  6. Salvar alterações.
  7. Feche o Visual Studio e reabri-la. Eu estou usando Visual Studio 2013, com EF 6 e eu tinha que fazer isso para obter os avisos para ir embora.

Eu não tenho que mudar meu ponto de vista a usar o ISNULL, NULLIF ou soluções alternativas COALESCE. Se você atualizar seu modelo de banco de dados, os avisos irão voltar a aparecer, mas vai embora se você fechar e reabrir VS. As alterações feitas no designer será preservado e não é afetado pela atualização.

Concordo com @Tillito, no entanto, na maioria dos casos ele vai sujar otimizador SQL e não vai usar índices corretos.

Pode ser óbvio para alguém, mas eu queimei horas resolvendo problemas de desempenho usando a solução Tillito. Vamos dizer que você tem a tabela:

 Create table OrderDetail
    (  
       Id int primary key,
       CustomerId int references Customer(Id),
       Amount decimal default(0)
    );
 Create index ix_customer on OrderDetail(CustomerId);

e sua visão é algo como isto

 Create view CustomerView
    As
      Select 
          IsNull(CustomerId, -1) as CustomerId, -- forcing EF to use it as key
          Sum(Amount) as Amount
      From OrderDetail
      Group by CustomerId

SQL otimizador não usará índice ix_customer e ele irá executar verificação de tabela em índice principal, mas se em vez de:

Group by CustomerId

você usa

Group by IsNull(CustomerId, -1)

fará MS SQL (pelo menos 2008) incluem indicador direito no plano.

Se

Este método funciona bem para mim. Eu uso ISNULL () para o campo de chave primária, e COALESCE () se o campo não deve ser a chave primária, mas também deve ter um valor não nulo. Este exemplo produz campo ID com uma chave primária não nulo. Os outros campos não são chaves, e têm (Nenhum) como seu atributo anulável.

SELECT      
ISNULL(P.ID, - 1) AS ID,  
COALESCE (P.PurchaseAgent, U.[User Nickname]) AS PurchaseAgent,  
COALESCE (P.PurchaseAuthority, 0) AS PurchaseAuthority,  
COALESCE (P.AgencyCode, '') AS AgencyCode,  
COALESCE (P.UserID, U.ID) AS UserID,  
COALESCE (P.AssignPOs, 'false') AS AssignPOs,  
COALESCE (P.AuthString, '') AS AuthString,  
COALESCE (P.AssignVendors, 'false') AS AssignVendors 
FROM Users AS U  
INNER JOIN Users AS AU ON U.Login = AU.UserName  
LEFT OUTER JOIN PurchaseAgents AS P ON U.ID = P.UserID

Se você realmente não tem uma chave primária, você pode falsificar um usando ROW_NUMBER para gerar uma chave pseudo que é ignorado pelo seu código. Por exemplo:

SELECT
ROW_NUMBER() OVER(ORDER BY A,B) AS Id,
A, B
FROM SOMETABLE

A corrente do gerador Entity Framework EDM irá criar uma chave composta de todos os campos não anuláveis ??em sua visão. A fim de obter controle sobre isso, você precisará modificar a vista e colunas da tabela subjacentes ajuste as colunas a anulável quando você não quer que eles sejam parte da chave primária. O oposto também é verdadeiro, como I encontrado, a chave gerada EDM causava problemas de duplicação de dados, de modo que tinha para definir uma coluna nula como não-nulo para forçar a chave composta no EDM para incluir essa coluna.

Para obter uma visão que eu tinha para mostrar apenas um coluna de chave primária eu criei uma segunda visão que apontavam para o primeiro e usado NULLIF para fazer os tipos anuláveis. Isso funcionou para mim para fazer a EF acho que houve apenas uma única chave primária na vista.

Não sei se isso irá ajudá-lo embora desde que eu não acredito que o EF irá aceitar uma entidade com chave primária NO.

Eu também recomendo, se você não quer mexer com o que deve ser a chave primária para incorporar ROW_NUMBER para sua seleção e defini-lo como chave primária e definir todas as outras colunas / memebers como não primário no modelo.

Devido aos problemas acima mencionados, eu prefiro funções de valor de tabela.

Se você tem este:

CREATE VIEW [dbo].[MyView] AS SELECT A, B FROM dbo.Something

criar esta:

CREATE FUNCTION MyFunction() RETURNS TABLE AS RETURN (SELECT * FROM [dbo].[MyView])

Em seguida, você simplesmente importar a função em vez da vista.

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