Question

Pour plusieurs raisons que je n'ai pas la liberté de parler, nous définissons une vue de notre base de données SQL Server 2005 comme suit:

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'idée est que Entity Framework créera une entité sur la base de cette requête, ce qu'il fait, mais il la génère avec une erreur indiquant ce qui suit:

  

Avertissement 6002: la table / vue 'Keystone_Local.dbo.MeterProvingStatisticsPoint' n'a pas de clé primaire définie. La clé a été déduite et la définition a été créée sous forme de table / vue en lecture seule.

Et il décide que le champ CompletedDateTime sera la clé primaire de cette entité.

Nous utilisons EdmGen pour générer le modèle. Existe-t-il un moyen de ne pas laisser le cadre d’entité inclure un champ de cette vue comme clé primaire?

Était-ce utile?

La solution

Nous avons eu le même problème et voici la solution:

Pour forcer le cadre de l'entité à utiliser une colonne en tant que clé primaire, utilisez ISNULL.

Pour forcer le cadre de l'entité à ne pas utiliser une colonne en tant que clé primaire, utilisez NULLIF.

Une méthode simple consiste à envelopper l'instruction select de votre vue dans une autre sélection.

Exemple:

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

Autres conseils

J'ai pu résoudre ce problème en utilisant le concepteur.

  1. Ouvrez le navigateur de modèle.
  2. Recherchez la vue dans le diagramme.
  3. Cliquez avec le bouton droit de la souris sur la clé primaire et assurez-vous que "Entity Key". est cochée.
  4. Sélectionner plusieurs fois toutes les clés non primaires. Utilisez les touches Ctrl ou Maj.
  5. Dans la fenêtre Propriétés (appuyez sur F4 si nécessaire pour le voir), modifiez le " Clé d’entité " déroulant jusqu'à False.
  6. Enregistrer les modifications.
  7. Fermez Visual Studio et rouvrez-le. J'utilise Visual Studio 2013 avec EF 6 et je devais le faire pour que les avertissements disparaissent.

Je n'ai pas eu besoin de changer d'avis pour utiliser les solutions de contournement ISNULL, NULLIF ou COALESCE. Si vous mettez à jour votre modèle à partir de la base de données, les avertissements réapparaîtront, mais disparaîtront si vous fermez et rouvrez VS. Les modifications apportées dans le concepteur seront préservées et ne seront pas affectées par l'actualisation.

Acceptez @Tillito, mais dans la plupart des cas, il optimisera l'optimiseur SQL et n'utilisera pas les index corrects.

Cela peut sembler évident à quelqu'un, mais j'ai passé des heures à résoudre des problèmes de performances avec la solution Tillito. Disons que vous avez la table:

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

et votre vue ressemble à quelque chose comme ça

 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'optimiseur SQL n'utilisera pas index ix_customer et effectuera une analyse de la table sur l'index principal, mais si au lieu de:

Group by CustomerId

vous utilisez

Group by IsNull(CustomerId, -1)

cela fera que MS SQL (au moins 2008) inclura le bon index dans le plan.

Si

Cette méthode fonctionne bien pour moi. J'utilise ISNULL () pour le champ de clé primaire et COALESCE () si le champ ne doit pas être la clé primaire, mais doit également avoir une valeur non nullable. Cet exemple renvoie un champ ID avec une clé primaire non Nullable. Les autres champs ne sont pas des clés et ont pour attribut Nullable (Aucun).

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

Si vous n'avez pas vraiment de clé primaire, vous pouvez en usurper une en utilisant ROW_NUMBER pour générer une pseudo-clé ignorée par votre code. Par exemple:

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

Le générateur EDM Entity Framework actuel créera une clé composite à partir de tous les champs non nullables de votre vue. Pour en prendre le contrôle, vous devrez modifier la vue et les colonnes de la table sous-jacente en définissant les colonnes sur nullable lorsque vous ne souhaitez pas qu'elles fassent partie de la clé primaire. Le contraire est également vrai. La clé générée par EDM posait des problèmes de duplication des données. Je devais donc définir une colonne nullable comme non-nullable pour forcer la clé composite dans le EDM à inclure cette colonne.

Pour obtenir une vue, je ne devais afficher que une colonne de clé primaire. J'ai créé une deuxième vue qui pointait vers la première et utilisait NULLIF pour rendre les types nullables. Cela a permis à l'EF de penser qu'il n'y avait qu'une seule clé primaire dans la vue.

Je ne sais pas si cela vous aidera, car je ne crois pas que le FE acceptera une entité sans clé primaire.

Je vous recommande également, si vous ne voulez pas vous mêler de ce qui devrait être la clé primaire, d'intégrer ROW_NUMBER à votre sélection, de la définir comme clé primaire et de définir toutes les autres colonnes / membres comme non primaires dans le modèle.

En raison des problèmes mentionnés ci-dessus, je préfère les fonctions de valeur de table.

Si vous avez ceci:

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

créer ceci:

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

Ensuite, vous importez simplement la fonction plutôt que la vue.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top