从存储过程传递和返回值以查看模型

时间:2018-08-03 09:48:40

标签: c# sql-server stored-procedures asp.net-core-mvc viewmodel

在此之前,我很欣赏Stackoverflow上有很多与存储过程相关的问题和答案,我知道,因为在过去的几天里,我读了很多,但是我仍然无法理解创建过程一个存储过程,它将把值返回到我的视图模型。

这个问题分为两个部分:

  1. 为什么我的代码无法成功运行,而是返回-1?
  2. 如果在您的帮助下,我越过了第一个问题,然后又如何将存储过程中返回的数据放入视图模型列表中?

我非常感谢社区可以给我的任何帮助...

  • 数据库名称为Discovery
  • 表名称为Person
  • 存储过程名称为uspGetOrgChart

我的桌子

CREATE TABLE Discovery.dbo.Person 
(
     ADID nvarchar(50) NOT NULL,
     First_Name nvarchar(50) NOT NULL,
     Last_Name nvarchar(50) NOT NULL,
     Report_To_ADID nvarchar(50) NULL,
     Position_ID int NULL,
     Role_ID int NULL,
     IGEMS nvarchar(50) NULL,
     DOB date NULL,
     Start_Date date NULL,
     Cost_Code nvarchar(50) NULL,

     PRIMARY KEY CLUSTERED (ADID),
     CONSTRAINT FK_Person_Position1 
         FOREIGN KEY (Position_ID) REFERENCES dbo.Position (Position_ID),
     CONSTRAINT FK_Person_Role 
         FOREIGN KEY (Role_ID) REFERENCES dbo.Role (Role_ID)
)
ON [PRIMARY]
GO 

我的存储过程当前如下:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[uspGetOrgChart]
    @ContactID VARCHAR(100) = 'NOE1WWD'
AS
BEGIN
    SET NOCOUNT ON;

    --grab id of @contactid
    DECLARE @Test varchar(36)
    SELECT @Test = (SELECT ADID FROM Person c1 WHERE c1.ADID = @ContactID)

    ;WITH StaffTree AS 
    ( 
        SELECT  
            c.ADID, 
            c.First_Name, 
            c.Last_Name,
            c.Report_To_ADID, 
            c.Report_To_ADID as Manager_ID,
            cc.First_Name AS Manager_First_Name, 
            cc.Last_Name as Manager_Last_Name, 
            cc.First_name + ' ' + cc.Last_name AS [ReportsTo], 
            c.First_Name + ' ' + c.Last_Name as EmployeeName,  
            1 AS LevelOf 
        FROM 
            Person c 
        LEFT OUTER JOIN 
            Person cc ON c.Report_To_ADID = cc.ADID 
        WHERE 
            c.ADID = @Test 
            OR (@Test IS NULL AND c.Report_To_ADID IS NULL) 

        UNION ALL 

        SELECT  
            s.ADID, 
            s.First_Name, 
            s.Last_Name, 
            s.Report_To_ADID, 
            t.ADID, 
            t.First_Name, 
            t.Last_Name, 
            t.First_Name + ' ' + t.Last_Name, 
            s.First_Name + ' ' + s.Last_Name,
            t.LevelOf + 1 
        FROM 
            StaffTree t 
        INNER JOIN 
            Person s ON t.ADID = s.Report_To_ADID 
        WHERE 
            s.Report_To_ADID = @Test 
            OR @Test IS NULL 
            OR t.LevelOf > 1 
    )
    SELECT * FROM StaffTree 
END

我已经测试过,并且上面的过程按预期工作,并返回以下列:

 ADID    
 First_Name
 Last_Name
 Report_To_ADID
 Manager_ID
 Manager_First_Name
 Manager_Last_Name
 ReportsTo
 EmployeeName
 LevelOf

我的视图模型称为vmNewOrgChart

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Discovery.ViewModels
{
    public class vmNewOrgChart
    {
        public string ADID { get; set; }
        public string First_Name { get; set; }
        public string Last_Name { get; set; }
        public string Report_To_Adid { get; set; }
        public string Manager_ID { get; set; }
        public string Manager_First_Name { get; set; }
        public string Manager_Last_Name { get; set; }
        public string ReportsTo { get; set; }
        public string EmployeeName { get; set; }
        public int LevelOf { get; set; }
    }
}

这是我开始完全陷入困境的地方

public IActionResult Orgchart(string id)
{
    var personIdParam = new SqlParameter("@ContactID", SqlDbType.VarChar);
    personIdParam.Value = id;

    var result = _context.Database.ExecuteSqlCommand("exec uspGetOrgChart", personIdParam);
}

上面的代码可以运行,但是结果的值为-1,这意味着它什么也不返回或出现了一些错误?

非常感谢您的协助

德里克

5 个答案:

答案 0 :(得分:0)

Database.ExecuteSqlCommand方法通常用于执行动作DML查询(self.prepareResponseObject(success: response.result.isSuccess, withData: value as Any, andError: nil) INSERTUPDATE),该方法返回这些操作中受影响的行数。如果要将DELETE查询结果返回到指定的模型类,则应使用Database.SqlQuery<TElement>,并将目标模型类设置为类型参数,如下所示:

SELECT

注意:默认情况下,如果没有记录/行受_context.Database.SqlQuery<vmNewOrgChart>("exec uspGetOrgChart", personIdParam); 影响,它将返回ExecuteSqlCommand值。

其他参考:Executing Raw SQL Queries Using Entity Framework

更新

对于Entity Framework Core,-1不可用,您可以使用Database.SqlQuery<TElement>或使用DbSet.FromSql,如下所示:

Database.GetDbConnection().CreateCommand()

相关问题:

How to run stored procedures in Entity Framework Core?

Database.SqlQuery Missing

答案 1 :(得分:0)

过程无法返回表。使用具有表返回值的函数代替:

CREATE FUNCTION  fnGetOrgChart()
RETURNS  @rtnTable TABLE 
(
---you fields
)
AS
BEGIN
DECLARE @TempTable table (id uniqueidentifier, name nvarchar(255)....)
insert into @myTable 
select from your stuff
--This select returns data
insert into @rtnTable
SELECT ID, name FROM @mytable 
return
END

有关具有表结果的功能的信息,请参阅Microsoft文档

然后拨打电话

var result = context.Database.SqlQuery<vmNewOrgChart>("select * from fnGetOrgChart()");

根据山本哲也的建议

否则,您必须调用存储的来填充临时表,然后从临时表中选择数据并刷新它

NB。您可以轻松地将参数传递给这些函数。简洁起见

答案 2 :(得分:0)

到目前为止谢谢大家

谢谢您,这看起来更接近工作了。当我使用代码时

using (_context)
{
using (var cmd = _context.Database.GetDbConnection().CreateCommand())
{
cmd.CommandText = "exec uspGetOrgChart";
cmd.CommandType = System.Data.CommandType.StoredProcedure;

var personIdParam = cmd.CreateParameter();
personIdParam.ParameterName = "ContactID";
personIdParam.Value = id;

cmd.Parameters.Add(personIdParam);

_context.Database.OpenConnection();
using (var result = cmd.ExecuteReader())
{
if (result.HasRows)
{
// do something with results

}
}
}

}

我收到一条错误消息,表明无法从此行找到存储过程,该过程肯定在那里并且可以工作

(var result = cmd.ExecuteReader())

我认为这是因为代码正在关闭并打开第二个连接,所以我注释掉了该行

_context.Database.OpenConnection();

这导致连接未打开的错误。

我当前的上下文称为

_Context 

并且正在整个应用程序的其余部分中使用,我真的必须创建一个全新的上下文和连接才能运行该过程。

谢谢 德里克

答案 3 :(得分:0)

谢谢大家的帮助,我成功使用此代码使Sproc成功运行

using (_context)
{
                using (var cmd = _context.Database.GetDbConnection().CreateCommand())
                {
                    cmd.CommandText = "uspGetOrgChart";
                    cmd.CommandType = System.Data.CommandType.StoredProcedure;

                    var personIdParam = cmd.CreateParameter();
                    personIdParam.ParameterName = "ContactID";
                    personIdParam.Value = id;

                    cmd.Parameters.Add(personIdParam);

                    _context.Database.OpenConnection();
                    using (var result = cmd.ExecuteReader())
                    {
                        if (result.HasRows)
                        {
                            // do something with results

                        }
                    }
                }

            }

命令文本中不需要“ exec”

答案 4 :(得分:0)

您可以使用此解决方案:

 using (var cmd = _db.Database.GetDbConnection().CreateCommand())
                {
                    cmd.CommandText = "dbo.GetCategories"; //sp name
                    cmd.CommandType = System.Data.CommandType.StoredProcedure;
                    _db.Database.OpenConnection();
                    using (var result = cmd.ExecuteReader())
                    {
                        if (result.HasRows)
                        {
                             var List= MapToList<Category>(result);
                        }
                    }
                }

public IList<T> MapToList<T>(DbDataReader dr)
        {
            var objList = new List<T>();
            var props = typeof(T).GetRuntimeProperties();

            var colMapping = dr.GetColumnSchema()
                .Where(x => props.Any(y => y.Name.ToLower() == x.ColumnName.ToLower()))
                .ToDictionary(key => key.ColumnName.ToLower());

            if (dr.HasRows)
            {
                while (dr.Read())
                {
                    T obj = Activator.CreateInstance<T>();
                    foreach (var prop in props)
                    {
                        if (colMapping.Any(a => a.Key.ToLower() == prop.Name.ToLower()))
                        {
                            var val = dr.GetValue(colMapping[prop.Name.ToLower()].ColumnOrdinal.Value);
                            prop.SetValue(obj, val == DBNull.Value ? null : val);
                        }
                    }
                    objList.Add(obj);
                }
            }
            return objList;
        }