5

我正在使用WebApi2和EntityFramework6開發服務。 我有一個傳統的SQLServer數據庫,我的服務必須使用。如何使用'hierarchyid'參數從EntityFramework 6調用存儲過程

該數據庫嚴重使用'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

在這裏黑暗中射擊......你能改變除了Nvarchar之外的Sproc,然後在Sproc的內部將這個值轉換成hirachyId嗎? – SimonGates

回答

3

不幸的是,MetaType.GetMetaTypeFromValue不允許添加類型(所有支持的類型都是硬編碼的)。 我認爲你可以用nvarchar參數和轉換完成你的目標。

在你的C#代碼:

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()); 

在你的程序中(我寫了裏面的一些測試代碼):

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 

此外,您還可以嘗試使用Microsoft.SqlServer.Types和SqlHierarchyId類型是這樣的:

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

但是,我認爲,這是錯誤的方向。

1

Oleg的答案是正確的,hierarchyid仍然沒有很好地整合到EF中,並且您應該使用.net中的字符串進行操作。這裏是一個更這是從HierarchyId的數據類型的第一天使用的方法:

存儲過程:

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數據上下文與應用使用普通的舊ADO.NET進行SP調用。也許你會寫其他的方式或使用小巧玲瓏代替,但這裏的主要思想是通過參數作爲字符串到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(); 
     } 
    } 
} 

然後調用該方法,任何其他存儲採用方法您的EF背景:

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

UPD:這裏是如何對傳統HierarchyId的過程調用擴展方法看起來像短小精悍(對我來說,它看起來比普通的ADO.NET好得多):

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"); 
      } 
     } 
相關問題