次のストアドプロシージャがあり、Function Importを実行しようとすると、ストアドプロシージャが列を返さないと表示されます。何が欠けていますか?助言がありますか?
手続き:
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
ストアドプロシージャの先頭に次の行を追加してみてください:
SET FMTONLY OFF
インポートが完了したら、これを削除できます。
ここで舞台裏で何が起こっていますか?
関数のインポートの実行中->列情報の取得... Visual Studioは、すべてのパラメーター値をNULLとしてストアドプロシージャを実行します(MS SQLプロファイラーを使用してこれをクロスチェックできます)。
手順1を実行すると、ストアドプロシージャの結果の列が、データ型と長さ情報とともに返されます。
列情報が取得されたら、「新しい複合型の作成」ボタンをクリックすると、SPの複合型が競合します。
あなたの場合、ストアドプロシージャのパラメーターはnullにできないため、Visual Studioの呼び出しは失敗し、列は返されません。
これをどのように処理しますか?
IF(1 = 0) BEGIN SET FMTONLY OFF @ param1がnullで@ param2がnullの場合 begin select cast(null as varchar(10))as Column1、 cast(null as bit)as Column2、 cast(null as decimal)as Column3 END END
正確に言うと(あなたの場合):
IF(1 = 0) BEGIN SET FMTONLY OFF @SearchStringがnullの場合、 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
完全に、単純な@benshabatnoam回答を作成するには、最初に次のコードを挿入します。
IF (1=2)
SET FMTONLY OFF
注:EF 6.1.3およびVisual Studio 2015 Update 3で動作します
一時テーブルが原因でこの問題が発生しています。必要なのは次のとおりです。1.ストアドプロシージャを変更して、一時テーブルなしで選択状態を返すようにします。 2.関数importに移動して、列情報を取得します。 3.ストアドプロシージャを元に戻します。
一時テーブルを使用している場合、エンティティ(EDMX)は何が起こっているのか理解できません。
したがって、列名で空の結果を返し、すべてのストアドプロシージャをコメントアウトしてSQLマネージャーで実行し、Visual Studioで複合型を取得します。保存後、ストアドプロシージャを元の状態(コメント化されていない状態)に戻します。
幸運を/
EFで列をすばやく簡単に見つける方法として、ストアドプロシージャのwhere句をコメント化し(TOP 1を追加してすべてを返さないようにする)、プロシージャをEFに追加して複合型を作成し、コメントを外します再びwhere句。
Sudhanshu Singhの答えに何か付け加えたいと思います。これは非常にうまく機能しますが、より複雑な構造がある場合は、テーブル宣言と組み合わせてください。
私は以下を正常に使用しました(ストアドプロシージャの最初に配置します):
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
注1=0
は、決して実行されないことを保証しますが、EFはそれから構造を差し引きます。
ストアドプロシージャを保存したら、Visual StudioでEDMXファイルを開き、データモデルを更新して、Entity Frameworksモデルブラウザーに移動します。モデルブラウザで、ストアドプロシージャを見つけ、[関数のインポートの編集]ダイアログを開き、[複雑なコレクションを返す]を選択して、[列情報を取得]ボタンをクリックします。
上で定義した構造が表示されます。含まれている場合は、[新しい複合型の作成]をクリックすると、ストアドプロシージャの名前で複合型が作成されます。 "MyStoredProc_Result"( "_Result"によって追加)。
同じダイアログの「Returns a collection of ... Complex」のコンボボックスで選択できるようになりました。
何かを更新する必要があるときはいつでも、SPを最初に更新してから、[関数インポートの編集]ダイアログに戻って[更新]ボタンをクリックできます(再作成する必要はありません)ゼロからすべて)。
これが唯一の正解であり、ここから見つけることができます
https://stackoverflow.com/a/27960583/51127
基本的に、EFは、行数または_-1
_がオンの場合は_NO COUNT
_、または_return <some integer>
_によって呼び出されたSQLストアドプロシージャから返されるものは常に返されることを認識しています。そのため、どのストアドプロシージャをインポートしても、型は常に_nullable<int>
_になります。 SQLストアドプロシージャからは整数のみを返すことができます。したがって、EFは関数を編集する方法を提供します。手動で編集した場合、更新時に上書きされると思いますが、確認できません。いずれにせよ、これはEFがこの問題に対処するために提供する機能です。
_.emdx
_ファイルをクリックします。 _Solution Explorer
_で選択したものである必要があります。 _Model Browser
_を選択します(Properties
の上にある_Solution Explorer
_タブのすぐ横)。 _Function Imports
_を展開し、ストアドプロシージャを見つけて右クリックし、[Edit
]をクリックします。変数のタイプを選択します。プリミティブ型にすることも、_Get Complex Type
_をクリックすることもできます。 _Get Column Information
_をクリックします。これはモデルの更新後も存続することを確認しました。
ストアドプロシージャから整数しか返せないのはなぜですか?本当にわかりませんが、この戻り定義では、整数のみを返すことができると説明しています: https://docs.Microsoft.com/en-us/sql/t-sql/language-elements/return- transact-sql?view = sql-server-ver15
この問題が発生したため、ユーザー定義のテーブルタイプを作成してそれを返す必要がありました。
CREATE TYPE T1 AS TABLE
( ID INT,
VendorName VARCHAR(255),
ItemName VARCHAR(255),
Type VARCHAR(2),
Sequence TINYINT
);
GO
ストアドプロシージャは次のようになります。
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
引用符なしでselectステートメントを追加し、ストアドプロシージャを実行して、モデルを更新し、関数のインポートを編集して、列情報を取得します。これにより、新しい列が表示されます。結果セットを更新してストアドプロシージャに戻り、追加した選択リストを削除します。そして、ストアドプロシージャを実行します。これにより、結果セットに列が入力されます。引用符なしで選択リストを追加する場所を以下に示します。
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
)
セット@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
これが誰かの役に立てば幸いです。