הראה שימוש ב-Stored Procedures בתוך C# API.
ניצור טבלה על מנת שנוכל לעבוד עליה.
יצירת טבלה חדשה
CREATE TABLE TestEmployee(ID int Identity(1,1) Primary Key,
Name varchar(100), Age int, Active int)
הרצת ה-query על ידי F5.
ננסה להביא את המידע מהטבלה, כמובן שהוא יגיע ריק, כי עכשיו יצרנו את הטבלה.
SELECT * FROM TestEmployee
יצירת פרוייקט VS
נעבור ל-Visual Studio וניצור פרוייקט חדש.
אנחנו נבצע 5 פעולות באמצעות ה-API. בחירת טבלה שלמה, בחירת רשומה על פי ID, יצירת רשומה חדשה, עדכון רשומה קיימת, ביטול רשומה קיימת.
כדי לבצע את הפעולות האלה, הוספתי controller עם פעולות בסיסיות.
בניית ה-API
נוסיף class של Employee. המבנה של ה-class יהיה תואם למבנה הטבלה שממנה אנחנו שואבים את הנתונים.
namespace SPWebAPI.Models;
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public int Active { get; set; }
}
נעבור ל-controller ונקבל את ה-configuration על מנת להשתמש ב-connection string.
public class HomeController : ControllerBase
{
private readonly IConfiguration _configuration;
private readonly string? _connectionString;
public HomeController(IConfiguration configuration) {
_configuration = configuration;
_connectionString = _configuration.GetValue<string>
("ConnectionStrings:webapi_conn");
}
}
כדי לחבר את ה-DB נבנה connection string בקובץ appsettings
לקובץ הזה נוסיף את ה-connection string. כדי למצוא את שם ה-server נחזור למנהל ה-SQL ונלחץ על connect->Database Engine.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"ConnectionStrings": {
"webapi_conn": "server=DESKTOP-PDVBMCF\\SQLEXPRESS;
database=master; Integrated Security=true; TrustServerCertificate=True"
},
"AllowedHosts": "*"
}
כדי להשתמש ב-SQL נתקין Nuget של Sql Client, ואת Microsoft.Extensions.Configuration. נוסיף ל-controller שלושה using.
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
מכיוון שאין לנו נתונים עדיין, נתחיל מפעולת post.
POST
ניצור את הפרוצדורה שמייצרת employee חדש.
CREATE PROC sp_AddEmployee(@Name VARCHAR(100), @Age INT, @Active INT)
AS
BEGIN
INSERT INTO TestEmployee(Name, Age, Active)
VALUES (@Name, @Age, @Active)
END;
נעבור ל-controller שמתחבר לפרוצדורה.
namespace SPWebAPI.Controllers;
[Route("api/[controller]")]
[ApiController]
public class HomeController : ControllerBase
{
private readonly IConfiguration _configuration;
private readonly string? _connectionString;
public HomeController(IConfiguration configuration) {
_configuration = configuration;
_connectionString = _configuration.GetValue<string>
("ConnectionStrings:webapi_conn");
}
[HttpPost]
[ProducesResponseType(201, Type = typeof(Employee))]
public async Task<ActionResult<Employee>> CreateEmployee(Employee employee) {
try {
SqlConnection con = new SqlConnection(_connectionString);
if (employee != null) {
SqlCommand cmd = new SqlCommand("sp_AddEmployee", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@Name", employee.Name);
cmd.Parameters.AddWithValue("@Age", employee.Age);
cmd.Parameters.AddWithValue("@Active", employee.Active);
con.Open();
int i = cmd.ExecuteNonQuery();
con.Close();
if (i > 0) {
return Ok("Data was created");
}
}
}
catch {
return NotFound("Data was not created");
}
}
}
אנחנו מייצרים SqlConnection עם ה-connection string שיצרנו.
מייצרים SqlCommand שמקבל את שם הפרוצדורה ואת החיבור ומגדירים את סוג הפקודה כפרוצדורה.
מחברים את הפרמטרים לפקודה.
פותחים חיבור, שולחים את הפקודה וסוגרים חיבור.
אם החיבור לא עובד אפשר לנסות להכנס להגדרות של החיבור ולסמן את Trust Server.
GET ALL
כשיש נתונים בתוך ה-DB אפשר לבצע פעולות select. ניצור את הפרוצדורה המתאימה.
CREATE PROC sp_GetAllEmployees
AS
BEGIN
SELECT * FROM TestEmployee
END;
נחזור ל-controller כדי לבנות את הפונקציה שמובילה להבאת הנתונים.
[HttpGet]
public List<Employee> GetAllEmployees() {
List<Employee> lstEmployees = new List<Employee>();
try {
SqlConnection con = new SqlConnection(_connectionString);
SqlDataAdapter da = new SqlDataAdapter("sp_GetAllEmployees", con);
DataTable dt = new DataTable();
da.Fill(dt);
if (dt.Rows.Count > 0) {
for(int i = 0; i < dt.Rows.Count; i++) {
Employee emp = new Employee();
emp.Id = Convert.ToInt32(dt.Rows[i]["Id"]);
emp.Name = dt.Rows[i]["Name"].ToString();
emp.Age = Convert.ToInt32(dt.Rows[i]["Age"]);
emp.Active = Convert.ToInt32(dt.Rows[i]["Active"]);
lstEmployees.Add(emp);
}
}
if (lstEmployees.Count > 0) {
return lstEmployees;
}
return null;
}
catch {
return null;
}
}
בצורה דומה נביא מידע לגבי עובד אחד.
GET BY ID
נכתוב את הפרוצדורה המתאימה.
CREATE PROC sp_GetEmployeeById(@Id INT)
AS
BEGIN
SELECT * FROM TestEmployee WHERE Id = @Id
END;
נפעיל את הפרוצדורה כדי שתישמר ונבנה את הפונקציה המתאימה ב-API.
[HttpGet("{id}")]
public Employee GetEmployeeById(int id) {
Employee emp = new Employee();
try {
SqlConnection con = new SqlConnection(_connectionString);
SqlDataAdapter da = new SqlDataAdapter("sp_GetEmployeeById", con);
da.SelectCommand.CommandType = CommandType.StoredProcedure;
da.SelectCommand.Parameters.AddWithValue("@Id", id);
DataTable dt = new DataTable();
da.Fill(dt);
if (dt.Rows.Count > 0) {
emp.Id = Convert.ToInt32(dt.Rows[0]["Id"]);
emp.Name = dt.Rows[0]["Name"].ToString();
emp.Age = Convert.ToInt32(dt.Rows[0]["Age"]);
emp.Active = Convert.ToInt32(dt.Rows[0]["Active"]);
}
if (emp != null) {
return emp;
}
return null;
}
catch {
return null;
}
}
UPDATE
עדכון רשומה על פי Id.
CREATE PROC sp_UpdateEmployee(@Id INT, @Name VARCHAR(100), @Age INT, @Active INT)
AS
BEGIN
UPDATE TestEmployee SET Name = @Name, Age = @Age, Active = @Active
WHERE Id = @Id
END;
והפונקציה המתאימה.
[HttpPut("{id}")]
public async Task<ActionResult<Employee>> UpdateEmployeeById(int id, Employee employee) {
try {
SqlConnection con = new SqlConnection(_connectionString);
if (employee != null) {
SqlCommand cmd = new SqlCommand("sp_UpdateEmployee", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@Id", id);
cmd.Parameters.AddWithValue("@Name", employee.Name);
cmd.Parameters.AddWithValue("@Age", employee.Age);
cmd.Parameters.AddWithValue("@Active", employee.Active);
con.Open();
int i = cmd.ExecuteNonQuery();
con.Close();
if (i > 0) {
return Ok("Data was updated");
}
}
return Created("api/products/{product.id}", employee);
}
catch {
return NotFound("Data was not updated");
}
}
DELETE
הפרוצדורה.
CREATE PROC sp_DeleteEmployee(@Id INT)
AS
BEGIN
DELETE FROM TestEmployee WHERE Id = @Id
END;
והפונקציה.
[HttpDelete("{id}")]
public string DeleteEmployeeById(int id, Employee employee) {
try {
SqlConnection con = new SqlConnection(_connectionString);
SqlCommand cmd = new SqlCommand("sp_DeleteEmployee", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@Id", id);
con.Open();
int i = cmd.ExecuteNonQuery();
con.Close();
if (i > 0) {
return ("Data was deleted");
}
return ("Data was not deleted");
}
catch {
return ("Data was not deleted");
}
}
הקוד פה לא מושלם, ויש מה לעבוד על הודעות השגיאה, אבל בגדול יש פה את כל הפעולות של עבודה מול ה-DB עם שימוש בפרוצדורות.