una - ¿Por qué no puede Entity Framework ver la información de columna de mi Procedimiento Almacenado?
no se puede construir el tipo de entidad o complejo en una consulta linq to entities (9)
Tengo el siguiente procedimiento almacenado y cuando intento la función de importación dice que mi procedimiento almacenado no devuelve columnas. ¿Qué me estoy perdiendo? ¿Alguna sugerencia?
El Proc:
ALTER PROCEDURE [healthc].[ev_kc_Products_Search]
(
@SearchString VARCHAR(1000)
)
AS
SET NOCOUNT ON
DECLARE @SQL VARCHAR(max),
@SQL1 VARCHAR(max),
@Tag VARCHAR(5)
CREATE TABLE #T
( ID INT,
VendorName VARCHAR(255),
ItemName VARCHAR(255),
Type VARCHAR(2),
Sequence TINYINT
)
SET @SQL = ''
INSERT #T
SELECT VendorID ID,
Name VendorName,
NULL ItemName,
''''V'''' Type,
0 Sequence
FROM tblVendors
WHERE ''+REPLACE(@SQL1,@Tag,''Name'')+''
UNION ALL
BLAH BLAH BLAH''
EXEC(@SQL)
SELECT ID, VendorName, ItemName, Type FROM #T
¿Qué está pasando aquí detrás de las escenas?
Mientras realiza la importación de funciones -> Obtener información de columna ... Visual Studio ejecuta el proceso almacenado con todos los valores de param como NULL (puede verificarlo a través de MS SQL Profiler).
Al hacer el paso 1, las columnas resultantes del proceso almacenado se devuelven con su tipo de datos y la información de la longitud.
Una vez que se obtiene la información de la columna, al hacer clic en el botón ''Crear nuevo tipo complejo'' se crea el tipo complejo del SP en disputa.
En su caso, los parámetros de proc almacenados no son anulables, por lo tanto, la llamada de Visual Studio falla y no devuelve ninguna columna.
¿Cómo manejar esto?
IF (1=0) BEGIN SET FMTONLY OFF if @param1 is null and @param2 is null then begin select cast(null as varchar(10)) as Column1, cast(null as bit) as Column2, cast(null as decimal) as Column3 END END
Para ser preciso (en tu caso):
IF (1=0) BEGIN SET FMTONLY OFF if @SearchString is null then BEGIN select cast(null as int) as ID, cast(null as varchar(255)) as VendorName, cast(null as varchar(255)) as ItemName, cast(null as varchar(2)) as Type END END
Como forma rápida y sucia de hacer que EF encuentre las columnas, comente la cláusula where de su proceso almacenado (quizás agregue un TOP 1 para evitar que devuelva todo), agregue el proceso a EF y cree el Tipo complejo, luego elimine el comentario del donde cláusula otra vez.
Intente agregar esta línea al comienzo de su procedimiento almacenado:
SET FMTONLY OFF
Puede eliminar esto después de que haya terminado de importar.
Me gustaría agregar algo a la respuesta de Sudhanshu Singh: funciona muy bien, pero si tienes estructuras más complejas, combínala con una declaración de tabla.
He utilizado lo siguiente con éxito (colóquelo al principio de su procedimiento almacenado):
CREATE PROCEDURE [EY].[MyStoredProc]
AS
BEGIN
SET NOCOUNT ON;
IF (1=0)
BEGIN
SET FMTONLY OFF
BEGIN
-- declaration + dummy query
-- to allow EF obtain complex data type:
DECLARE @MyStoredProcResult TABLE(
ID INT,
VendorName VARCHAR(255),
ItemName VARCHAR(255),
Type VARCHAR(2),
Sequence TINYINT
);
SELECT * FROM @MyStoredProcResult WHERE (1=0)
END
END
-- your code follows here (SELECT ... FROM ...)
-- this code must return the same columns/data types
--
-- if you require a temp table / table variable like the one above
-- anyway, add the results during processing to @MyStoredProcResult
-- and then your last statement in the SP can be
-- SELECT * FROM @MyStoredProcResult
END
Tenga en cuenta que el 1=0
garantiza que nunca se ejecuta, pero el EF le resta la estructura.
Después de haber guardado el procedimiento almacenado, abra el archivo EDMX en Visual Studio, actualice el modelo de datos, vaya al navegador del modelo Entity Frameworks. En el navegador de modelos, ubique su procedimiento almacenado, abra el cuadro de diálogo "Editar importación de funciones", seleccione "Devuelve una colección de ... Complejo", luego haga clic en el botón "Obtener información de columna".
Debería aparecer la estructura como se define arriba. Si lo hace, haga clic en "Crear nuevo tipo complejo" y creará uno con el nombre del procedimiento almacenado, por ejemplo, "MyStoredProc_Result" (anexado por "_Result").
Ahora puede seleccionarlo en el cuadro combinado de "Devuelve una colección de ... Complejo" en el mismo cuadro de diálogo.
Siempre que necesite actualizar algo, actualice primero el SP, luego puede volver al cuadro de diálogo Importar función de edición y hacer clic en el botón "Actualizar" (no necesita volver a crear todo desde cero).
Si está utilizando una tabla temporal, la Entidad (EDMX) no puede entender lo que está sucediendo.
Así que devuelva el resultado vacío con el nombre de la columna, comente todo su procedimiento almacenado y ejecútelo en el administrador sql, luego obtenga el tipo complejo en Visual Studio. Después de guardar, devuelva su procedimiento almacenado a su estado original (sin comentar).
buena suerte/
Simplemente agregue la instrucción select sin la cita, ejecute el proceso almacenado, obtenga la actualización del modelo, edite la función de importación y obtenga información de la columna. Esto debería llenar las nuevas columnas. Actualice el conjunto de resultados y regrese a su proceso almacenado y elimine la lista de selección que acaba de agregar. Y ejecuta el proceso almacenado. De esta forma, sus columnas se llenarán en el conjunto de resultados. Vea a continuación dónde agregar la lista de selección sin presupuesto.
ALTER PROCEDURE [healthc].[ev_kc_Products_Search]
(
@SearchString VARCHAR(1000)
)
AS
SET NOCOUNT ON;
SELECT VendorID ID,
Name VendorName,
NULL ItemName,
''''V'''' Type,
0 Sequence
FROM tblVendors
DECLARE @SQL VARCHAR(max),
@SQL1 VARCHAR(max),
@Tag VARCHAR(5)
CREATE TABLE #T
( ID INT,
VendorName VARCHAR(255),
ItemName VARCHAR(255),
Type VARCHAR(2),
Sequence TINYINT
)
SET @SQL = ''
INSERT #T
SELECT VendorID ID,
Name VendorName,
NULL ItemName,
''''V'''' Type,
0 Sequence
FROM tblVendors
WHERE ''+REPLACE(@SQL1,@Tag,''Name'')+''
UNION ALL
BLAH BLAH BLAH''
EXEC (@SQL)
SELECT ID, VendorName, ItemName, Type FROM #T
Espero que esto ayude a alguien por ahí.
Tienes este problema debido a la tabla de temperatura. Todo lo que necesita hacer es: 1. Modificar su procedimiento almacenado para devolver el statemant selecto sin la tabla temporal. 2. Vaya a la importación de funciones y obtenga la información de la columna. 3. Cambie su procedimiento almacenado a original.
Tuve este problema, lo que tuve que hacer fue crear un tipo de tabla definido por el usuario y devolverlo.
CREATE TYPE T1 AS TABLE
( ID INT,
VendorName VARCHAR(255),
ItemName VARCHAR(255),
Type VARCHAR(2),
Sequence TINYINT
);
GO
Su procedimiento almacenado se verá así:
ALTER PROCEDURE [healthc].[ev_kc_Products_Search]
(
@SearchString VARCHAR(1000)
)
AS
SET NOCOUNT ON
DECLARE @SQL VARCHAR(max),
@SQL1 VARCHAR(max),
@Tag VARCHAR(5)
@T [schema].T1
SET @SQL = ''SELECT VendorID ID,
Name VendorName,
NULL ItemName,
''''V'''' Type,
0 Sequence
FROM tblVendors
WHERE ''+REPLACE(@SQL1,@Tag,''Name'')+''
UNION ALL
BLAH BLAH BLAH''
INSERT INTO @T
EXEC(@SQL)
SELECT ID, VendorName, ItemName, Type FROM @T
en completitud y haciendo una respuesta simple de @benshabatnoam, simplemente coloque el siguiente código al principio:
IF (1=2)
SET FMTONLY OFF
Nota: funciona en EF 6.1.3 y Visual Studio 2015 Actualización 3