Vista Entity Framework y SQL Server


Por varias razones de las que no tengo la libertad de hablar, estamos definiendo una vista en nuestra base de datos Sql Server 2005 de la siguiente manera:

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

La idea es que Entity Framework creará una entidad basada en esta consulta, lo cual hace, pero la genera con un error que indica lo siguiente:

Advertencia 6002: La tabla/vista 'Keystone_Local.dbo.MeterProvingStatisticsPoint' no tiene definida una clave primaria. La clave se ha inferido y la definición fue creado como una tabla/vista de solo lectura.

Y decide que el campo CompletedDateTime será esta clave primaria de entidad.

Estamos usando EdmGen para generar el modelo. ¿Hay alguna manera de que entity framework no incluya ningún campo de esta vista como clave principal?

Author: abatishchev, 2009-06-18

9 answers

Teníamos el mismo problema y esta es la solución:

Para forzar a entity framework a usar una columna como clave primaria, use ISNULL.

Para forzar a entity framework a no usar una columna como clave primaria, use NULLIF.

Una manera fácil de aplicar esto es envolver la instrucción select de su vista en otra select.

Ejemplo:

SELECT
  ISNULL(MyPrimaryID,-999) MyPrimaryID,
  NULLIF(AnotherProperty,'') AnotherProperty
  FROM ( ... ) AS temp
 231
Author: Tillito,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-26 17:00:42

Pude resolver esto usando el diseñador.

  1. Abra el Navegador de modelos.
  2. Encuentre la vista en el diagrama.
  3. Haga clic derecho en la clave principal y asegúrese de que "Clave de entidad" esté marcada.
  4. Selección múltiple de todas las claves no primarias. Utilice las teclas Ctrl o Shift.
  5. En la ventana de Propiedades (presione F4 si es necesario para verlo), cambie "Clave de entidad desplegable" a False.
  6. Guarda los cambios.
  7. Cierre Visual Studio y vuelva a abrirlo. Estoy usando Visual Studio 2013 con EF 6 y tuve que hacer esto para que las advertencias desaparecieran.

No tuve que cambiar mi vista para usar las soluciones alternativas ISNULL, NULLIF o COALESCE. Si actualiza su modelo desde la base de datos, las advertencias volverán a aparecer, pero desaparecerán si cierra y vuelve a abrir, frente a los cambios realizados en el diseñador que se conservarán y no se verán afectados por la actualización.

 61
Author: Casey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-18 19:04:28

Está de acuerdo con @Tillito, sin embargo, en la mayoría de los casos se foul SQL optimizer y no va a utilizar los índices correctos.

Puede ser obvio para alguien, pero quemé horas resolviendo problemas de rendimiento usando la solución Tillito. Digamos que tienes la tabla:

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

Y tu punto de vista es algo así

 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 no utilizará index ix_customer y realizará análisis de tabla en el índice primario, pero si en lugar de:

Group by CustomerId

Utiliza

Group by IsNull(CustomerId, -1)

Hará MS SQL (al menos 2008) incluye el índice derecho en el plan.

Si

 45
Author: Val Bakhtin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-10 17:57:53

Este método funciona bien para mí. Uso ISNULL() para el campo de clave primaria, y COALESCE() si el campo no debe ser la clave primaria, pero también debe tener un valor no nullable. Este ejemplo produce un campo ID con una clave primaria no anulable. Los otros campos no son claves, y tienen (None) como su atributo 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

Si realmente no tiene una clave primaria, puede falsificar una usando ROW_NUMBER para generar una pseudo-clave que es ignorada por su código. Por ejemplo:

SELECT
ROW_NUMBER() OVER(ORDER BY A,B) AS Id,
A, B
FROM SOMETABLE
 8
Author: SpazDude,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-29 23:07:46

El generador EDM actual de Entity Framework creará una clave compuesta a partir de todos los campos no anulables en su vista. Para obtener control sobre esto, deberá modificar las columnas de la vista y de la tabla subyacente estableciendo las columnas en nullable cuando no desee que formen parte de la clave principal. Lo contrario también es cierto, ya que me encontré con que la clave generada por EDM estaba causando problemas de duplicación de datos, por lo que tuve que definir una columna nullable como no nullable para forzar la clave compuesta en el EDM para incluir esa columna.

 4
Author: Annagram,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-07 18:54:56
 3
Author: RBarryYoung,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-18 15:55:19

Para obtener una vista solo tenía que mostrar una columna de clave primaria Creé una segunda vista que apuntaba a la primera y usé NULLIF para hacer que los tipos fueran nullables. Esto funcionó para mí para hacer que la EF pensara que solo había una sola clave primaria en la vista.

No estoy seguro de si esto le ayudará, ya que no creo que EF acepte una entidad sin clave primaria.

 3
Author: Nick Gotch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-22 23:02:49

También le recomiendo si no quiere meterse con lo que debería ser la clave primaria incorporar ROW_NUMBER a su selección y configurarlo como clave primaria y establecer todas las demás columnas/memebers como no primarias en el modelo.

 2
Author: Santhos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-25 13:22:19

Debido a los problemas mencionados anteriormente, prefiero las funciones de valor de tabla.

Si tienes esto:

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

Crea esto:

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

Entonces simplemente importa la función en lugar de la vista.

 1
Author: Ray,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-03 20:14:51