5

WebApi2とEntityFramework6を使用してサービスを開発しています。 サービスが動作する必要がある従来のSQLServer DBがあります。'hierarchyid'パラメータでEntityFramework 6からストアドプロシージャを呼び出す方法

DBは 'hierarchyid'データ型を頻繁に使用しており、この型はDBのストアドプロシージャで内部的に使用されます。

EF6は 'hierarchyid'データ型をサポートしていないようですので、私はthis forkに 'hierarchyid'のサポートを追加しました。

DBからの検索が 'hierarchyid'型でうまくいっている間、私の問題は、 'hierarchyid'をパラメータとして必要とするストアドプロシージャにあります。

ストアドプロシージャは、次のようになります。このストアドプロシージャを呼び出すための

CREATE PROCEDURE [dbo].[GetSomethingByNodeId] 
    (
     @startingRoot HIERARCHYID 
     ,@return HIERARCHYID OUTPUT 
    ) 

私のクライアントコードは次のようになります。

var param1 = new SqlParameter("@startingRoot", new HierarchyId("/")); 
var param2 = new SqlParameter{ ParameterName = "@return", Value = 0, Direction = ParameterDirection.Output }; 

var obj = context.Database.SqlQuery<HierarchyId>("GetSomethingByNodeId" @startingRoot, @return out", param1, param2).ToList(); 

しかし残念ながら、このクエリを呼び出すと言う例外がスローされます。

An unhandled exception of type 'System.ArgumentException' occurred in EntityFramework.SqlServer.dll 

Additional information: No mapping exists from object type System.Data.Entity.Hierarchy.HierarchyId to a known managed provider native type. 

どのように私はこの作品を作ることができますか?

+0

ここでは暗闇の中で撮影しています... SprocをNvarchar以外のものに変更して、その値をSprocの内部でhirachyIdにキャストできますか? – SimonGates

答えて

3

残念ながら、MetaType.GetMetaTypeFromValueはタイプを追加できません(サポートされているすべてのタイプはハードコードされています)。 あなたは、あなたの目標をnvarcharのパラメータとコンバージョンで達成できると思います。あなたのC#コードで

:あなたはこのようなMicrosoft.SqlServer.TypesとSqlHierarchyIdタイプを使用しようとすることができ、また

CREATE PROCEDURE [dbo].[GetSomethingByNodeId] 
    (
     @startingRoot nvarchar(max), @return nvarchar(max) OUTPUT 
    ) 
as 
declare @hid hierarchyid = hierarchyid::Parse('/1/') 
select @return = @hid.ToString() 

declare @root hierarchyid = hierarchyid::Parse(@startingRoot) 
select @root as field 

:あなたの手順で

var param1 = new SqlParameter("@startingRoot", "/1/"); 
var param2 = new SqlParameter { ParameterName = "@return", Value = "", Size = 1000, Direction = ParameterDirection.Output }; 

var ids = context.Database.SqlQuery<HierarchyId>("GetSomethingByNodeId @startingRoot, @return out", param1, param2).ToList(); 
var returnedId = new HierarchyId(param2.Value.ToString()); 

は(私の中にいくつかのテストコードを書いた)

var sqlHierarchyId = SqlHierarchyId.Parse("/"); 
var param1 = new SqlParameter("@startingRoot", sqlHierarchyId) { UdtTypeName = "HierarchyId" }; 

しかし、これは間違った方向だと思います。

1

Olegの答えは正しいですが、hierarchyidはまだEFに統合されておらず、.netで文字列を操作する必要があります。

ストアドプロシージャ:

CREATE PROCEDURE GetSomethingByNodeId 
    @startingRoot hierarchyid, -- you don't need to use nvarchar here. String which will come from the application will be converted to hierarchyId implicitly 
    @return nvarchar(500) OUTPUT 
AS 
BEGIN 
SELECT @return = @startingRoot.GetAncestor(1).ToString(); 

END

あなたとあなたのEFデータコンテキストの部分クラスを追加しているアプリケーションで、ここでhierarchyid型のデータ型の最初の日から使用されたもう一つのアプローチがあります普通の古いADO.NETを使用しているSP呼び出し。おそらくあなたは、この他の方法を書きますか、代わりにDapperのを使用していますが、ここでの主なアイデアは、SQL Serverに文字列としてパラメータを渡して、それは暗黙的にhierarchyid型に変換されます:

public partial class TestEntities 
{ 
    public string GetSomethingByNodeId(string startingRoot) 
    { 
     using (var connection = new SqlConnection(this.Database.Connection.ConnectionString)) 
     { 
      var command = new SqlCommand("GetSomethingByNodeId", connection); 
      command.CommandType = CommandType.StoredProcedure; 
      command.Parameters.AddWithValue("@startingRoot", startingRoot); 
      var outParameter = new SqlParameter("@return", SqlDbType.NVarChar, 500); 
      outParameter.Direction = ParameterDirection.Output; 
      command.Parameters.Add(outParameter); 
      connection.Open(); 
      command.ExecuteNonQuery(); 

      return outParameter.Value.ToString(); 
     } 
    } 
} 

は、次に格納されている任意の他のように、このメソッドを呼び出します

using (var context = new TestEntities()) 
{ 
    var s = context.GetSomethingByNodeId("/1/1.3/"); 
} 

UPD:あなたのEFコンテキスト使用手順ここでは、レガシーのためにどのように拡張メソッドがあるのhierarchyid型プロシージャ・コールは(私のためとして、それはプレーンなADO.NETよりもはるかに良く見える)Dapperのを次のようになります。

public string GetSomethingByNodeId(string startingRoot) 
     { 
      using (var connection = new SqlConnection(this.Database.Connection.ConnectionString)) 
      { 
       var parameters = new DynamicParameters(); 
       parameters.Add("startingRoot", startingRoot); 
       parameters.Add("return", null, DbType.String, ParameterDirection.Output, 500); 
       connection.Open(); 
       connection.Execute("GetSomethingByNodeId", parameters, commandType: CommandType.StoredProcedure); 

       return parameters.Get<string>("return"); 
      } 
     } 
関連する問題