使用带有 C# 的 Entity Framework 6 调用现有的存储过程

Posted

技术标签:

【中文标题】使用带有 C# 的 Entity Framework 6 调用现有的存储过程【英文标题】:Calling existing Stored procedure using Entity Framework 6 with C# 【发布时间】:2017-07-26 16:38:43 【问题描述】:

我需要知道如何使用c#调用实体框架6 Code First中的现有存储过程。

以下是我正在使用的程序:

CREATE PROCEDURE proc_getEmployees 
    @departmentname varchar(50),
    @sortCol varchar(30),
    @sortdir varchar(25),
    @searchString varchar(50)
AS
BEGIN
    SET NOCOUNT ON;
    declare @strSQl varchar(1000);
    declare @strSQlwhere varchar(500);
    declare @strSelectEndPart varchar(100);
    
    set @strSQl = ';WITH employeetable as 
                (
                    select ROW_NUMBER() OVER (ORDER BY '+@sortCol+' '+@sortdir+' ) AS RowNumber,COUNT(*) over() as TotalRecords, ID,FirstName,LastName,Designation,DepartmentName,Contact,EmailAddress,Location from Employees ';
    set @strSQlwhere = 'where DepartmentName = '''+@departmentname+'''';
    set @strSQlwhere = @strSQlwhere+ ' and (Id like ''%' + @searchString + '%'' Or FirstName like ''%' + @searchString + '%'' Or LastName like ''%' + @searchString + '%'' Or Designation like ''%' + @searchString + '%'' Or DepartmentName like ''%' + @searchString + '%'' Or Contact like ''%' + @searchString + '%'' Or EmailAddress like ''%' + @searchString + '%'' Or Location like ''%' + @searchString + '%'')';
    set @strSelectEndPart =') select * from employeetable';
                    
    set @strSQl = @strSQl +@strSQlwhere+@strSelectEndPart;
    execute (@strSQl);
END
GO

我正在查询的表是员工,其结构如下:

Column          Type    Length
ID              int       4
FirstName       varchar   50
LastName        varchar   50
Designation     varchar   50
DepartmentName  varchar   50
Contact         varchar   50
EmailAddress    varchar   50
Location        varchar   50

DBContext 类如下:

public class DevelopmentTestDatabaseContext :DbContext

    public DevelopmentTestDatabaseContext() : base("name =DevelopmentTestDatabaseContext")
    

    
    public virtual DbSet<Employee> EmployeeData  get; set; 
    

存储过程调用方法如下:

public void GetEmployeeDataUsingProcedure()

    object[] parameters = new SqlParameter[4];
    List<EmployeeResultSet> lstEmployees = new List<EmployeeResultSet>();
    try
    
        using (var db = new DevelopmentTestDatabaseContext())
        
            SqlParameter param = new SqlParameter("@departmentname", "IT");
            parameters[0] = param;
            param = new SqlParameter("@sortCol", "ID");
            parameters[1] = param;
            param = new SqlParameter("@sortdir", "asc");
            parameters[2] = param;
            param = new SqlParameter("@searchString", "ope");
            parameters[3] = param;

            var results = db.Database.SqlQuery<EmployeeResultSet>("proc_getEmployees @departmentname, @sortCol, @sortdir, @searchString", parameters);
            db.Database.Log = query => System.Diagnostics.Debug.Write(query);
            lstEmployees = results.ToList();
        
    
    catch (Exception ex)
    

    

为存储过程结果集定义了如下类:

public class EmployeeResultSet

    public int rowNumber  get; set; 
    public int totalRecords  get; set; 
    public int ID  get; set; 
    public string FirstName  get; set; 
    public string LastName  get; set; 
    public string Designation  get; set; 
    public string DepartmentName  get; set; 
    public string Contact  get; set; 
    public string EmailAddress  get; set; 
    public string Location  get; set; 

请让我知道在调用存储过程之前是否需要做任何其他事情。我是 EF6 的新手,遇到了问题。代码中缺少什么?我需要对任何课程进行一些更改吗?

【问题讨论】:

如果我没记错的话,你所有的参数都是new SqlParameter("@searchString", "ope")。你应该做parameters[0] = new SqlParameter("@key", "value"); parameters[1] = new SqlParameter("@key2", "value2");等等。本质上你是在说parameters[0]-[4] = param。然后你改变它每一行。因此,您正在更改数组中的值。 【参考方案1】:

我可以说的一个问题是在您调用该过程的方法中。您将数组的所有元素设置为等于param,但您不断更改param。您的所有元素都将等于param 的最终状态。试试这个:

public void GetEmployeeDataUsingProcedure()

    object[] parameters = new SqlParameter[4];
    List<EmployeeResultSet> lstEmployees = new List<EmployeeResultSet>();
    try
    
        using (var db = new DevelopmentTestDatabaseContext())
        
            parameters[0] = new SqlParameter("@departmentname", "IT");
            parameters[1] = new SqlParameter("@sortCol", "ID");
            parameters[2] = new SqlParameter("@sortdir", "asc");
            parameters[3] = new SqlParameter("@searchString", "ope");

            var results = db.Database.SqlQuery<EmployeeResultSet>("proc_getEmployees @departmentname, @sortCol, @sortdir, @searchString", parameters);
            db.Database.Log = query => System.Diagnostics.Debug.Write(query);
            lstEmployees = results.ToList();
        
    
    catch (Exception ex)
    
        //log it or something
    

可能还有其他问题,但无需过多研究,我需要有关您遇到的特定错误或行为的更多信息。

您也可以尝试输入数据库的全名:

"MyDatabase.MySchema.proc_getEmployees @departmentname, @sortCol, @sortdir, @searchString"

编辑根据您的 cmets:

快速闪避,我找到了this。从本质上讲,如果您在查询中将您的号码转换为int,您应该没问题。所以而不是:

select * from employeetable

试试:

select CAST(RowNumber as int) as RowNumber, 
    CAST(TotalRecords as int) as TotalRecords, 
    CAST(ID as int) as ID, 
    FirstName, 
    LastName, 
    Designation, 
    DepartmentName, 
    Contact, 
    EmailAddress, 
    Location 
from employeetable

【讨论】:

感谢您提供详细信息,尝试了提到的参数选项,得到错误为从具体化的“System.Int64”类型到“System.Int32”类型的指定转换无效。另外,当我尝试记录查询时 嗯,也许可以尝试将您的课程 ints 更改为 longs,请参阅此处:***.com/questions/3845205/how-to-use-int64-in-c-sharp 和此处:***.com/questions/32264382/… 仍然出现同样的错误。还有一件事要澄清,就像在我调用存储过程的语句中一样, 仍然出现同样的错误。还有一件事要澄清,因为我在代码中调用过程时使用 EmployeeResultSet 是否需要在 DevelopmentTestDatabaseContext 类中定义,因为我只有一个属性,即这个 public virtual DbSet EmployeeData get;放; 。如果有问题请告诉我 不,根据文档,msdn.microsoft.com/en-us/library/…,它可以是任何类型,包括非实体。【参考方案2】:

顺便说一句,但您实际上没有必要使用动态 SQL。特别是当搜索条件是字符串时,坚持参数化查询更安全。在您的情况下,您可以执行以下操作:

;WITH employeetable as 
(
    select 
    CASE WHEN @sortDir = 'asc' THEN
    ROW_NUMBER() OVER (ORDER BY 
    CASE WHEN @sortCol = 'ID' THEN ID END,
    CASE WHEN @sortCol = 'FirstName' THEN FirstName END,
    CASE WHEN @sortCol = 'LastName' THEN LastName END,
    CASE WHEN @sortCol = 'Designation' THEN Designation END,
    CASE WHEN @sortCol = 'DepartmentName' THEN DepartmentName END,
    CASE WHEN @sortCol = 'Contact' THEN Contact END,
    CASE WHEN @sortCol = 'EmailAddress' THEN EmailAddress END,
    CASE WHEN @sortCol = 'Location' THEN Location END
    ASC) ELSE ROW_NUMBER() OVER (ORDER BY  
    CASE WHEN @sortCol = 'ID' THEN ID END,
    CASE WHEN @sortCol = 'FirstName' THEN FirstName END,
    CASE WHEN @sortCol = 'LastName' THEN LastName END,
    CASE WHEN @sortCol = 'Designation' THEN Designation END,
    CASE WHEN @sortCol = 'DepartmentName' THEN DepartmentName END,
    CASE WHEN @sortCol = 'Contact' THEN Contact END,
    CASE WHEN @sortCol = 'EmailAddress' THEN EmailAddress END,
    CASE WHEN @sortCol = 'Location' THEN Location END
    DESC) END AS RowNumber,
    COUNT(*) over() as TotalRecords, ID,FirstName,LastName,Designation,
    DepartmentName,Contact,EmailAddress,Location from Employees
    where DepartmentName = @departmentname and 
    (Id like '%' + @searchString + '%' Or FirstName like '%' 
    + @searchString + '%' Or LastName like '%' + @searchString + '%' 
    Or Designation like '%' + @searchString + '%' Or 
    DepartmentName like '%' + @searchString + '%' Or 
    Contact like '%' + @searchString + '%' Or 
    EmailAddress like '%' + @searchString + '%' Or 
    Location like '%' + @searchString + '%')
)
select * from employeetable

【讨论】:

感谢您的输入将进行这些更改,但我的问题是为什么我在调用存储过程时出现错误,过程在 sql server 中运行良好 我得到的错误是从物化的“System.Int64”类型到“System.Int32”类型的指定转换无效。也尝试更改该类的数据类型,但仍然没有运气

以上是关于使用带有 C# 的 Entity Framework 6 调用现有的存储过程的主要内容,如果未能解决你的问题,请参考以下文章

带有 Entity Framework Core 的 SQLite 很慢

如何使用 C# 将 Include 动态添加到 ObjectSet<Entity>?

c# Enumerable中Aggregate和Join的使用

如何在 ASP.NET MVC 5、Entity Framework 6 中使用流利的 API 映射表?

C# Entity Framework中的IQueryable和IQueryProvider详解

C# Entity Framework中的IQueryable和IQueryProvider详解