5

ich mit WebApi2 und EntityFramework6 einen Dienst entwickle. Ich habe ein Vermächtnis SQLServer DB, die meinen Dienst mit arbeiten müssen.Wie gespeicherte Prozedur von EntityFramework 6 mit ‚hierarchyid‘ Parameter nennen

Die DB-Datentyp stark den ‚hierarchyid‘ verwendet, und diese Art der intern in DB gespeicherten Prozeduren verwendet wird.

Scheint wie EF6 nicht 'hierarchyid' Datentyp unterstützt, so dass ich this fork verwendet, die Unterstützung für 'hierarchyid' hinzugefügt.

Während das Abrufen von der DB mit dem 'hierarchyid' Typ funktioniert, ist mein Problem mit den Stored Procedures, die eine 'hierarchyid' als Parameter benötigen.

Die gespeicherte Prozedur sieht wie folgt aus:

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

Mein Client-Code diese gespeicherte Prozedur zum Aufrufen wie folgt aussieht:

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

Aber leider diese Abfrage Aufruf löst eine Ausnahme, die sagt:

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. 

Irgendwelche Ideen, wie ich das schaffen kann?

+0

Hier im Dunkeln geschossen ... Kannst du den Sproc auf einen Nvarchar umstellen und dann den Wert innerhalb des Sprocs in eine HirachyId umwandeln? – SimonGates

Antwort

3

Leider MetaType.GetMetaTypeFromValue nicht Typen erlaubt hinzuzufügen (alle unterstützten Typen sind fest einprogrammiert). Ich glaube, Sie Ihr Ziel mit nvarchar Parameter und Conversions erreichen können.

In Ihrem C# -Code:

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

In der Prozedur (Ich schrieb einigen Test-Code innen):

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 

Sie können aber auch versuchen Microsoft.SqlServer.Types und wie diese SqlHierarchyId Typen zu verwenden:

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

Aber ich denke, das ist eine falsche Richtung.

1

Olegs Antwort ist korrekt, hierarchyid ist immer noch nicht in die EF integriert, und Sie sollten mit Strings in .net arbeiten. Hier ist ein weiterer Ansatz, der von den ersten Tagen des hierarchyid Datentypen verwendet wurde:

Stored Procedure:

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

In einer Anwendung, die Sie hinzufügen eine partielle Klasse für Ihren EF Datenkontext mit der SP Anruf plain old ADO.NET verwenden.Wahrscheinlich werden Sie diese andere Art und Weise schreiben oder Dapper stattdessen verwenden, aber die Grundidee ist hier vorbei Parameter als Zeichenfolge zu SQL Server, und es wird auf die hierarchyid konvertieren implizit:

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

Dann rufen Sie diese Methode als jede andere gespeicherte Verfahren Ihres EF Zusammenhang mit:

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

UPD: hier ist, wie die Erweiterungsmethode für ältere hierarchyid Prozeduraufruf mit Dapper aussehen wird (wie für mich viel besser als normales ADO.NET aussieht):

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"); 
      } 
     } 
Verwandte Themen