Domanda

Per diversi motivi di cui non ho la libertà di cui parlare, stiamo definendo una vista sul nostro database SQL Server 2005 in questo modo:

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

L'idea è che Entity Framework creerà un'entità basata su questa query, che lo fa, ma la genera con un errore che indica quanto segue:

  

Avviso 6002: la tabella / vista 'Keystone_Local.dbo.MeterProvingStatisticsPoint' non ha una chiave primaria definita. La chiave è stata dedotta e la definizione è stata creata come tabella / vista di sola lettura.

E decide che il campo CompletedDateTime sarà la chiave primaria di questa entità.

Stiamo usando EdmGen per generare il modello. Esiste un modo per evitare che il framework di entità includa un campo di questa vista come chiave primaria?

È stato utile?

Soluzione

Abbiamo avuto lo stesso problema e questa è la soluzione:

Per forzare il framework di entità a usare una colonna come chiave primaria, usa ISNULL.

Per forzare il framework di entità a non utilizzare una colonna come chiave primaria, utilizzare NULLIF.

Un modo semplice per applicare questo è avvolgere l'istruzione select della vista in un'altra selezione.

Esempio:

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

Altri suggerimenti

Sono stato in grado di risolverlo usando il designer.

  1. Apri il Browser modello.
  2. Trova la vista nel diagramma.
  3. Fai clic con il pulsante destro del mouse sulla chiave primaria e assicurati che " Chiave entità " è selezionato.
  4. Selezione multipla di tutte le chiavi non primarie. Utilizzare i tasti Ctrl o Maiusc.
  5. Nella finestra Proprietà (premere F4 se necessario per vederlo), modificare " Chiave entità " menu a discesa su False.
  6. Salva le modifiche.
  7. Chiudi Visual Studio e riaprilo. Sto usando Visual Studio 2013 con EF 6 e ho dovuto farlo per far sparire gli avvisi.

Non ho dovuto modificare la mia vista per usare le soluzioni alternative ISNULL, NULLIF o COALESCE. Se aggiorni il tuo modello dal database, gli avvisi riappariranno, ma scompariranno se chiudi e riapri VS. Le modifiche apportate alla finestra di progettazione verranno mantenute e non saranno influenzate dall'aggiornamento.

Concordo con @Tillito, tuttavia nella maggior parte dei casi si sporcherà l'ottimizzatore SQL e non utilizzerà gli indici corretti.

Potrebbe essere ovvio per qualcuno, ma ho bruciato ore a risolvere problemi di prestazioni usando la soluzione Tillito. Diciamo che hai il tavolo:

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

e la tua visione è qualcosa del genere

 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

L'ottimizzatore SQL non utilizzerà l'indice ix_customer e eseguirà la scansione della tabella sull'indice primario, ma se invece di:

Group by CustomerId

usi

Group by IsNull(CustomerId, -1)

farà in modo che MS SQL (almeno il 2008) includa l'indice giusto nel piano.

Se

Questo metodo funziona bene per me. Uso ISNULL () per il campo chiave primaria e COALESCE () se il campo non deve essere la chiave primaria, ma dovrebbe anche avere un valore non annullabile. In questo esempio viene generato un campo ID con una chiave primaria non annullabile. Gli altri campi non sono chiavi e hanno (Nessuno) come attributo Nullable.

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 in realtà non hai una chiave primaria, puoi falsificarne una usando ROW_NUMBER per generare una pseudo-chiave che viene ignorata dal tuo codice. Ad esempio:

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

L'attuale generatore EDM Entity Framework creerà una chiave composita da tutti i campi non annullabili nella vista. Per ottenere il controllo su questo, è necessario modificare la vista e le colonne della tabella sottostante impostando le colonne su nullable quando non si desidera che facciano parte della chiave primaria. È vero anche il contrario, come ho riscontrato, la chiave generata da EDM stava causando problemi di duplicazione dei dati, quindi ho dovuto definire una colonna nullable come non nullable per forzare la chiave composita nell'EDM a includere quella colonna.

Per ottenere una vista ho dovuto mostrare solo una colonna chiave primaria ho creato una seconda vista che puntava alla prima e ho usato NULLIF per rendere i tipi nulla. Ciò ha funzionato per me per far pensare all'EF che nella vista fosse presente un'unica chiave primaria.

Non sono sicuro se questo ti aiuterà, poiché non credo che l'EF accetterà un'entità senza chiave primaria.

Consiglio anche se non vuoi fare confusione con quella che dovrebbe essere la chiave primaria per incorporare ROW_NUMBER nella tua selezione e impostarla come chiave primaria e impostare tutte le altre colonne / memebers come non primarie nel modello.

A causa dei problemi di cui sopra, preferisco le funzioni dei valori di tabella.

Se hai questo:

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

crea questo:

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

Quindi devi semplicemente importare la funzione anziché la vista.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top