Entity Framework et SQL Server View

Pour plusieurs raisons dont je n’ai pas la liberté de parler, nous définissons une vue de notre firebase database 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é basée sur cette requête, ce qu’elle fait, mais elle le 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 en tant que table / vue en lecture seule.

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

Nous utilisons EdmGen pour générer le modèle. Y a-t-il un moyen de ne pas inclure de champ de cette vue dans la structure d’entité comme clé primaire?

    Nous avons eu le même problème et c’est la solution:

    Pour forcer le framework d’entité à utiliser une colonne comme clé primaire, utilisez ISNULL.

    Pour forcer le framework d’entité à ne pas utiliser une colonne comme clé primaire, utilisez NULLIF.

    Un moyen simple d’appliquer cette méthode 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 

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

    1. Ouvrez le navigateur de modèles.
    2. Trouvez la vue dans le diagramme.
    3. Cliquez avec le bouton droit sur la clé primaire et assurez-vous que “Entity Key” est coché.
    4. Multi-sélectionner toutes les clés non primaires. Utilisez les touches Ctrl ou Shift.
    5. Dans la fenêtre Propriétés (appuyez sur F4 si nécessaire pour le voir), définissez la liste déroulante “Entity Key” sur False.
    6. Sauvegarder 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 à modifier ma vue pour utiliser les solutions de contournement ISNULL, NULLIF ou COALESCE. Si vous mettez à jour votre modèle depuis la firebase database, les avertissements réapparaîtront, mais disparaîtront si vous fermez et rouvrez VS. Les modifications que vous avez apscopes au concepteur seront préservées et non affectées par l’actualisation.

    D’accord avec @Tillito, cependant, dans la plupart des cas, cela endommagera l’optimiseur SQL et n’utilisera pas d’index corrects.

    Cela peut être évident pour quelqu’un, mais j’ai brûlé des heures à résoudre des problèmes de performance en utilisant 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 est 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 

    Sql optimizer n’utilisera pas l’index ix_customer et effectuera une parsing de la table sur l’index primaire, mais si:

     Group by CustomerId 

    tu utilises

     Group by IsNull(CustomerId, -1) 

    Cela fera de MS SQL (au moins 2008) un bon index dans le plan.

    Si

    Cette méthode fonctionne bien pour moi. J’utilise ISNULL () pour le champ 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 le champ ID avec une clé primaire non nullable. Les autres champs ne sont pas des clés et ont (Aucun) leur atsortingbut 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.AuthSsortingng, '') AS AuthSsortingng, 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 ne possédez pas vraiment de clé primaire, vous pouvez en créer une en utilisant ROW_NUMBER pour générer une pseudo-clé qui est 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 dans votre vue. Pour en prendre le contrôle, vous devez modifier les colonnes de la vue et 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. L’inverse est également vrai, comme je l’ai rencontré, la clé générée par EDM provoquait des problèmes de duplication de données, j’ai donc dû définir une colonne nullable comme non nullable pour forcer la clé composite de l’EDM à inclure cette colonne.

    Pour obtenir une vue, je devais seulement afficher une colonne de clé primaire J’ai créé une seconde vue qui pointe vers le premier et a utilisé NULLIF pour rendre les types nullables. Cela a fonctionné pour que le FE pense qu’il n’y avait qu’une seule clé primaire dans la vue.

    Je ne suis pas sûr que cela vous aidera, car je ne crois pas que le FE acceptera une entité sans clé primaire.

    Je recommande également si vous ne voulez pas gâcher ce qui devrait être la clé primaire pour incorporer ROW_NUMBER à votre sélection et la définir comme clé primaire et définir toutes les autres colonnes / memebers 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 tableau.

    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.