SQL Server trigger with EF TransactionScope - c#

Can anyone help me with problem with trigger on insert/update when inserting records to tables in a SQL Server database using EF and TransactionScope?
When I try the trigger in SQL Server Management Studio, it's working fine, also the app is working fine when there is no trigger or trigger is disabled.
I have 2 SQL Server tables, Orders and OrdersParts. I have a trigger on OrdersParts that I use to update another table based calculations of inserted records.
Is any workaround so I can make something in SQL Server trigger because I don't want to change the code?
Thank you...
Here is my code in VS, I get fail in repository.CreateOrder
public void CreateOrder(Guid userId, int? referenceId, Cart cart, OrderInfo orderInfo)
{
using (TransactionScope transaction = new TransactionScope())
{
var order = new Orders
{
UserId = userId,
ReferenceId = referenceId,
Status = (int)OrderStatus.Created,
PaymentType = (int)orderInfo.PaymentType,
ShippingType = orderInfo.ShippingType,
Comment = orderInfo.Comment,
DateTimeCreated = DateTime.Now
};
context.Orders.Add(order);
context.SaveChanges();
foreach (var line in cart.Lines)
{
context.OrdersParts.Add(new OrdersParts
{
PartId = line.Product.ProductId,
OrderId = order.OrderId,
Price = line.Product.Price,
Quantity = line.Quantity
});
}
context.SaveChanges();
transaction.Complete();
}
}
Here is My CreateOrder HTTP Post Method:
[HttpPost]
public ActionResult CreateOrder(Cart cart, OrderInfo orderInfo)
{
var result = new JsonResult<bool>() { Status = true };
var user = Membership.GetUser(User.Identity.Name);
var userId = (Guid)user.ProviderUserKey;
try
{
var userDetails = usersRepository.Members.FirstOrDefault(x => x.UserId == userId);
if (!userDetails.ClientId.HasValue)
{
result.Status = false;
result.Result = false;
result.Message = "Errror Client";
return Json(result);
}
int clientId = userDetails.ClientId.Value;
// Create order in WareHouse
string message = null;
int? referenceId;
if (!integrationService.CreateOrder(clientId, cart, orderInfo, out referenceId, out message))
{
result.Status = false;
result.Result = false;
result.Message = message;
return Json(result);
}
repository.CreateOrder(userId, referenceId, cart, orderInfo);
cart.Clear();
result.Result = true;
result.Message = "";
}
catch
{
result.Status = false;
result.Result = false;
result.Message = "Error on creating order! Please try again.";
}
return Json(result);
}
Trigger:
ALTER TRIGGER [dbo].[UpdateComment] ON [dbo].[OrdersParts]
WITH EXECUTE AS CALLER
AFTER INSERT, UPDATE
AS
BEGIN
DECLARE #OrderID INT;
DECLARE #QDefWareH INT;
DECLARE #OrderedQuantity INT;
DECLARE #ArticleID VARCHAR(20);
DECLARE my_Cursor CURSOR FAST_FORWARD
FOR
SELECT a.OrderId ,
a.Quantity ,
b.RefSifra
FROM INSERTED a
LEFT OUTER JOIN dbo.Accounting b ON b.PartId = a.PartId;
OPEN my_Cursor;
FETCH NEXT FROM my_Cursor INTO #OrderID, #OrderedQuantity, #ArticleID;
EXEC #QDefWareH = _SPArtInDefWarehouse #ArticleID;
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #QDefWareH;
IF ( #OrderedQuantity > #QDefWareH )
BEGIN
UPDATE dbo.Orders
SET Comment = IIF(Comment IS NULL, #ArticleID, Comment
+ ' ;' + CHAR(13) + CHAR(10) + #ArticleID)
WHERE OrderId = #OrderID;
END;
FETCH NEXT FROM my_Cursor INTO #OrderID, #OrderedQuantity,
#ArticleID;
END;
CLOSE my_Cursor;
DEALLOCATE my_Cursor;
END;

Related

Returning a value before committing transaction and (UPDLOCK, HOLDLOCK)

I need to check if a record exists - if yes: then returns its id, if not: creates a new record and returns its id. I am using WITH (UPDLOCK, HOLDLOCK) in SELECT to prevent from duplicates (it creates lock). I wonder if I should commit the transaction if a record exists in a database for realising the lock?
using (SqlConnection connection = new SqlConnection("..."))
{
await connection.OpenAsync();
using (var transaction = connection.BeginTransaction())
{
var locationId = await connection.QueryFirstOrDefaultAsync<int?>(
"SELECT id
FROM Locations WITH (UPDLOCK, HOLDLOCK)
WHERE regionId = #RegionId", new { RegionId = 1 }, transaction: transaction
);
if (locationId.HasValue)
{
//transaction.Commit(); // should I commit the transaction here?
return locationId.Value;
}
var location = new Location()
{
Name = "test",
RegionId = 1
};
var newLocationid = await connection.InsertAsync<int>(location, transaction);
transaction.Commit();
return newLocationid;
}
}
should I commit the transaction here?
Yes. Otherwise it will roll back when the using block completes. That won’t matter in this particular case, but it’s better to be explicit. And if this transaction was part of a larger transaction, the whole thing would get rolled back.
You do not need a transaction here.
using (SqlConnection connection = new SqlConnection("..."))
{
await connection.OpenAsync();
/* The lock hints you had here makes no sense. */
var locationId = await connection.QueryFirstOrDefaultAsync<int?>(
"SELECT id
FROM Locations
WHERE regionId = #RegionId", new { RegionId = 1 }
);
if (locationId.HasValue)
{
return locationId.Value;
}
var location = new Location()
{
Name = "test",
RegionId = 1
};
/* INSERT has an implicit transaction
only need to use a transaction if you have multiple DML statements (i.e. INSERT, UPDATE or DELETE statments) */
var newLocationid = await connection.InsertAsync<int>(location);
return newLocationid;
}
}
Well you don't have to begin transaction while querying. You can rewrite your code as below:
using (SqlConnection connection = new SqlConnection("..."))
{
await connection.OpenAsync();
var locationId = await connection.QueryFirstOrDefaultAsync<int?>(
"SELECT id
FROM Locations WITH (UPDLOCK, HOLDLOCK)
WHERE regionId = #RegionId", new { RegionId = 1 });
if (locationId.HasValue)
{
return locationId.Value;
}
using (var transaction = connection.BeginTransaction())
{
var location = new Location()
{
Name = "test",
RegionId = 1
};
var newLocationid = await connection.InsertAsync<int>(location, transaction);
transaction.Commit();
}
return newLocationid;
}

How to query multiple result in specify value in dapper

I want return all records when data.Task = 0 in this query. how to do it?
var data = SqlConn.ConnectSQL().Query("Select TicketNo, PickName From TaxiTicket Where DriverID = #ID AND Status = #State",
new { ID = find.Account, State = data.Task });
var data = SqlConn.ConnectSQL().Query("Select TicketNo, PickName From TaxiTicket
Where DriverID = #ID AND (Status = case #State when 0 then Status else #state end)",
new { ID = find.Account, State = data.Task });
this only addresses your point of question, how you prepare and pass parameters is another issue. you seem to have some weird assignment using same data variable.

ASP.NET MVC Get the ID of Inserted Item by stored procedure

I am using Store Procedure to insert in the table FASEC. I want get the last id inserted after call Store Procedure.
How Can I get the last id inserted after calling Store procedure?
fasec.IDFASEC always 0
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateFASEC([Bind(Prefix = "Item1")] FASEC fasec)
{
if (ModelState.IsValid)
{
ObjectParameter p_Result = new ObjectParameter("p_Result", typeof(Int32));
db.SPINSFASEC(fasec.FECHAFASEC, fasec.DIAGNOSTICOFINAL, fasec.VIGENTE, fasec.IDCIE10,
fasec.IDPRESTADOR, fasec.HISTORIALMEDICO, fasec.FECHAINICIO, fasec.FECHATERMINO,
fasec.FECHARENOVACION, fasec.IDBENEFICIARIO, fasec.IDTIPOEVALUACION, fasec.IDESTADOFASEC,
fasec.RESOLUCION, fasec.OBSERVACION, fasec.RUTAUTORIZO, fasec.IDEMPRESA, p_Result);
if (p_Result.Value == DBNull.Value)
{
return RedirectToAction("Index", new { mostrarError = 1});
}
else
{
db.SaveChanges();
var lastId = fasec.IDFASEC;
}
}
return RedirectToAction("Index");
}
Stored Procedure:
create or replace PROCEDURE spInsFasec
(p_FechaFasec IN FASEC.FECHAFASEC%TYPE,
p_DiagnosticoFinal IN FASEC.DIAGNOSTICOFINAL%TYPE,
p_Vigente IN FASEC.VIGENTE%TYPE,
p_IdCie10 IN FASEC.IDCIE10%TYPE,
p_IdPrestador IN FASEC.IDPRESTADOR%TYPE,
p_HistorialMedico IN FASEC.HISTORIALMEDICO%TYPE,
p_FechaInicio IN FASEC.FECHAINICIO%TYPE,
p_FechaTermino IN FASEC.FECHATERMINO%TYPE,
p_FechaRenovacion IN FASEC.FECHARENOVACION%TYPE,
p_IdBeneficiario IN FASEC.IDBENEFICIARIO%TYPE,
p_IdTipoEvaluacion IN FASEC.IDTIPOEVALUACION%TYPE,
p_IdEstadoFasec IN FASEC.IDESTADOFASEC%TYPE,
p_Resolucion IN FASEC.RESOLUCION%TYPE,
p_Observacion IN FASEC.OBSERVACION%TYPE,
p_RutAutorizo IN FASEC.RUTAUTORIZO%TYPE,
p_IdEmpresa IN FASEC.IDEMPRESA%TYPE,
p_result OUT NUMBER) IS
cCeroValor CONSTANT NUMBER := 0;
cUnoValor CONSTANT NUMBER := 1;
vCont NUMBER(10);
vIDFASEC NUMBER := 0;
BEGIN
SELECT COUNT(*) INTO vCont
FROM COBERTURA
WHERE ACTIVO = cUnoValor AND
IDEMPRESA = p_IdEmpresa;
IF vCont > 0 THEN
INSERT INTO FASEC(
FECHAFASEC,
DIAGNOSTICOFINAL,
VIGENTE,
IDCIE10,
IDPRESTADOR,
HISTORIALMEDICO,
FECHAINICIO,
FECHATERMINO,
FECHARENOVACION,
IDBENEFICIARIO,
IDTIPOEVALUACION,
IDESTADOFASEC,
RESOLUCION,
OBSERVACION,
RUTAUTORIZO,
IDEMPRESA)
VALUES
(p_FechaFasec,
p_DiagnosticoFinal,
p_Vigente,
p_IdCie10,
p_IdPrestador,
p_HistorialMedico,
p_FechaInicio,
p_FechaTermino,
p_FechaRenovacion,
p_IdBeneficiario,
p_IdTipoEvaluacion,
p_IdEstadoFasec,
p_Resolucion,
p_Observacion,
p_RutAutorizo,
p_IdEmpresa)
RETURNING IDFASEC INTO vIDFASEC;
INSERT INTO COBERTURAFASEC
(IDCOBERTURAFASEC,
IDFASEC,
IDCOBERTURA,
PORCENTAJEREEMBOSO)
SELECT SEQ_COBERTURAFASEC.NEXTVAL,
vIDFASEC,
IDCOBERTURA,
PORCENTAJEREEMBOSO
FROM COBERTURA
WHERE ACTIVO = cUnoValor AND
IDEMPRESA = p_IdEmpresa;
p_result := 1;
END IF;
END;
You can get inserted value from stored procedure using output
INSERT INTO FASEC(
FECHAFASEC,
DIAGNOSTICOFINAL,
VIGENTE,
)
output inserted.FECHAFASEC //inserted.coloumn Name
VALUES(
)

Entity Framework Get Table By Name

I am looking for ways to do LINQ on a table selected in runtime via string variable.
This is what I have so far using reflection:
private Entities ctx = new Entities();
public List<AtsPlatform> GetAtsPlatformByName(string atsPlatformName)
{
List<AtsPlatform> atsPlatform = null;
System.Reflection.PropertyInfo propertyInfo = ctx.GetType().GetProperty(atsPlatformName.ToLower());
var platform = propertyInfo.GetValue(ctx, null);
// it fails here highlighting "platform" with error that reads "Error 1 Could not find an implementation of the query pattern for source type 'System.Data.Objects.ObjectQuery'. 'Select' not found. Consider explicitly specifying the type of the range variable 'ats'."
atsPlatform = ((from ats in platform select new AtsPlatform { RequestNumber = ats.RequestNumber, NumberOfFail = ats.NumberOfFail, NumberOfFailWithCR = ats.NumberOfFailWithCR, NumberOfTestCase = ats.NumberOfTestCase }).ToList());
return atsPlatform;
}
In my model class, I have:
public class AtsPlatform
{
public string Name { get; set; }
public string RequestNumber { get; set; }
public Int32? NumberOfFail { get; set; }
public Int32? NumberOfTestCase { get; set; }
public Int32? NumberOfFailWithCR { get; set; }
}
In Database, I have the following tables: "ats1", "ats2", "ats3" .. "atsN" where each of them has the same entity fields as the properties defined in "AtsPlatform"
What I would like to do is simply:
List<AtsPlatform> a1 = GetAtsPlatformByName("ats1");
List<AtsPlatform> a2 = GetAtsPlatformByName("ats2");
List<AtsPlatform> aN = GetAtsPlatformByName("atsN");
I could use "switch" but this makes the code less expandable and requires update whenever new "ats(N+1)" gets created.
My 2 days of research lead me nowhere but back to ground zero. I'm quite stuck.
PLEASE HELP! Thanks!
Instead of reflection, how about using the SqlQuery function?
So
List<AtsPlatform> GetAtsPlatformByName(int index)
{
using (var ctx = new Entities())
{
return ctx.Database.SqlQuery<AtsPlatform>("SELECT * FROM dbo.ats" + index)
.ToList();
}
}
Also, there is no change tracking on the entities using the SqlQuery method on the Database object (which is ok in your case I suppose since the AtsPlatform class only contains primitive properties).
For changes tracking you will need to use the DbSet SqlQuery method, and may need to mix some reflection in.
Sorry for my late response as I wondered off trying out different solutions:
Solution #1: Master Table
As suggested by #Alexw, creating a Master Table works the best ONLY if you are allowed to change the design of the db. I'm currently working with the db owner to make this change. Due to dependencies, this change has to wait till next phase.
Meanwhile, I've created mock db to exercise this approach.
Solution #2: Raw Query
As Suggested by #Umair, raw query will do the job. I've created a class that handles raw sql query.
public class AtsRawQuery
{
private string ConnetionString = "";
public AtsRawQuery(string connectionString)
{
this.ConnetionString = connectionString;
}
public List<List<string>> Query(string queryString)
{
List<List<string>> results = null;
MySqlConnection conn = null;
MySqlDataReader rdr = null;
try
{
conn = new MySqlConnection(this.ConnetionString);
conn.Open();
MySqlCommand cmd = new MySqlCommand(queryString, conn);
rdr = cmd.ExecuteReader();
if (rdr.HasRows)
{
results = new List<List<string>>();
while (rdr.Read())
{
List<string> curr_result = new List<string>();
for (int columnIndex = 0; columnIndex <= rdr.FieldCount - 1; columnIndex++)
{
curr_result.Add(rdr.GetString(columnIndex));
}
results.Add(curr_result);
}
}
}
catch (MySqlException ex)
{
Console.WriteLine(ex.Message);
return null;
}
finally
{
if (rdr != null)
{
rdr.Close();
}
if (conn != null)
{
conn.Close();
}
}
return results;
}
}
This class returns a 2 dimension list for later consumption.
In my model class, I added a parser method:
public class AtsPlatform
{
public string Name { get; set; }
public string RequestNumber { get; set; }
public Int32? NumberOfFail { get; set; }
public Int32? NumberOfTestCase { get; set; }
public Int32? NumberOfFailWithCR { get; set; }
public void Parse(string name, string requestNumber, string numberOfFail, string numberOfTestCase, string numberOfFailWithCR)
{
Int32 temp;
this.Name = name;
this.RequestNumber = requestNumber;
this.NumberOfFail = (Int32.TryParse(numberOfFail, out temp)) ? Int32.Parse(numberOfFail) : 0;
this.NumberOfTestCase = (Int32.TryParse(numberOfTestCase, out temp)) ? Int32.Parse(numberOfTestCase) : 0;
this.NumberOfFailWithCR = (Int32.TryParse(numberOfFailWithCR, out temp)) ? Int32.Parse(numberOfFailWithCR) : 0;
}
}
Solution #2(b): Raw Query using ExecuteStoreCommand
public List<AtsPlatform> GetAtsPlatformByName(string atsPlatformName)
{
List<AtsPlatform> atsPlatforms = null;
string stm = String.Format("SELECT RequestNumber, NumberOfFail, NumberOfTestCase, NumberOfFailWithCR FROM {0}", atsPlatformName);
atsPlatforms = new List<AtsPlatform>();
foreach (AtsPlatform ats in ctx.ExecuteStoreQuery<AtsPlatform>(stm))
{
atsPlatforms.Add(ats);
}
return atsPlatforms;
}
Solution #3: Stored Procedure
I've created a stored procedure and here is the code:
DELIMITER $$
CREATE PROCEDURE `UnionAtsTables`()
BEGIN
DECLARE atsName VARCHAR(10);
DECLARE atsIndex INT;
SET atsIndex = 1;
SET #qry = '';
WHILE atsIndex > 0 DO
SET atsName =concat('ATS',atsIndex);
IF sf_is_table(atsName) = 1 THEN
Set #temp_qry = CONCAT('SELECT *, ''', atsName ,''' As TestPlatform FROM ', atsName, ' WHERE RequestNumber <> ''''' );
If #qry = '' THEN
SET #qry = #temp_qry;
ELSE
SET #qry = CONCAT(#qry, ' UNION ', #temp_qry);
END IF;
ELSE
SET atsIndex = -1;
END IF;
SET atsIndex = atsIndex + 1;
END WHILE;
DROP TABLE IF EXISTS ats_all;
SET #CreateTempTableQuery = CONCAT('CREATE TEMPORARY TABLE ats_all AS ', #qry ,'');
PREPARE stmt1 FROM #CreateTempTableQuery;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
ALTER TABLE ats_all DROP COLUMN ExecOrder;
ALTER TABLE ats_all ADD ExecOrder INT PRIMARY KEY AUTO_INCREMENT;
ALTER TABLE ats_all auto_increment = 0;
END
Here is the function I found online that checks if table exists in db.
DELIMITER $$
CREATE FUNCTION `sf_is_table`(`in_table` varchar(255)) RETURNS tinyint(4)
BEGIN
/**
* Check if table exists in database in use
*
* #name sf_is_table
* #author Shay Anderson 08.13 <http://www.shayanderson.com>
*
* #param in_table (table name to check)
* #return TINYINT (1 = table exists, 0 = table does not exist)
*/
# table exists flag
DECLARE is_table BOOLEAN DEFAULT FALSE;
# table count
DECLARE table_count INT DEFAULT 0;
# database name
SET #db = NULL;
# set database name
SELECT
DATABASE()
INTO
#db;
# check for valid database and table names
IF LENGTH(#db) > 0 AND LENGTH(in_table) > 0 THEN
# execute query to check if table exists in DB schema
SELECT COUNT(1) INTO table_count
FROM information_schema.`TABLES`
WHERE TABLE_SCHEMA = #db
AND TABLE_NAME = in_table;
# set if table exists
IF table_count > 0 THEN
SET is_table = TRUE;
END IF;
END IF;
RETURN is_table;
END
Conclusion:
Thank you everyone for your suggestions.
I decided to use Solution #2 since it does not cause as much impact to the db performance as Solution #3 and it does not require db redesign as Solution #1.
I don't think what you are doing will work like that. You should create an entity based on a single 'master' table, eg. Ats
Once you have done this you will have a property on your Entities class called Ats. You can now use this property to select the entities using a raw SQL query like this.
var atsName = "ats1";
using (var context = new Entities())
{
var blogs = context.Ats.SqlQuery(string.Format("SELECT * FROM {0}", atsName)).ToList();
}
Alternatively you could try this (I am assuming the property type is DBSet as you haven't specified it in the question)
var platform = propertyInfo.GetValue(ctx, null) as DBSet<Ats>;
atsPlatform = platform.Select(ats => new A new AtsPlatform { RequestNumber = ats.RequestNumber, NumberOfFail = ats.NumberOfFail, NumberOfFailWithCR = ats.NumberOfFailWithCR, NumberOfTestCase = ats.NumberOfTestCase }).ToList();
return atsPlatform;

parameter value passsing in c# asp.net

I have got 2 asp pages. Firstly i get logged in through log in page and 2nd page is home page where i got few buttons of some tasks. Along with that i got user details which consists of FULLNAME,ADDRESS,CELL NUMBER,BLOOD GROUP and EMAILID, this should be displayed dynamically in their particular labels from DATABASE once the user logs in using his username and password.
I have written Query for this within the GetLoginDetails Stored Procedure. I have to display Employee Name,his Last Login Date,Time etc. once his log in and enters home page in the same way i should get user details.
ALTER PROCEDURE [dbo].[GetLastLogin]
#LoggedInUser nvarchar(50),
#FullName nvarchar(50),
#Address nvarchar(50),
#MobileNumber bigint,
#EmailID nvarchar(50),
#BloodGroup nvarchar(50),
#EmpName nvarchar(50)
As
Declare #LastLogin int
Set #LastLogin = (Select MAX(AccessID)from dbo.ACCESS_INFO where Flag = 1)
Select Access_Date, Access_Time from dbo.ACCESS_INFO where LoggedInUser = #LoggedInUser and AccessID = #LastLogin
Update dbo.EmployeeData
Set Empname = #EmpName
where FullName = #FullName and Address = #Address and MobileNumber = #MobileNumber and EmailID = #EmailID and BloodGroup = #BloodGroup ;
im getting error saying tht ("Procedure or function 'GetLastLogin' expects parameter '#FullName', which was not supplied.") please help me out
back end code
protected void Page_Load(object sender, EventArgs e)
{
if (Session["Username"] != null)
{
try
{
MTMSDTO objc = new MTMSDTO();
LblLogdInUser.Text = Session["EmpName"].ToString();
LblUser.Text = Session["Username"].ToString();
objc.LoggedInUser = LblUser.Text;
DataSet laslogin = obj.GetLastLogin(objc);
DataView LasLogin = new DataView();
LasLogin.Table = laslogin.Tables[0];
GrdLasLogin.DataSource = LasLogin;
GrdLasLogin.DataBind();
if (!IsPostBack)
{
int lastlog = GrdLasLogin.Rows.Count;
if (lastlog == 0)
{
LblLastLoginD.Text = "This is your First Login";
DateTime today = System.DateTime.Now.Date;
LblToday.Text = today.ToString();
LblTime.Text = System.DateTime.Now.ToLongTimeString();
objc.LoggedInUser = LblLogdInUser.Text;
objc.AccessDate = Convert.ToDateTime(LblToday.Text);
objc.AccessTime = Convert.ToDateTime(LblTime.Text);
objc.AccessStatus = "New Login";
objc.AccessFlag = 1;
int accessinfo = obj.InsertAccessInfo(objc);
}
else
{
LblLastLoginD.Text = Convert.ToDateTime(GrdLasLogin.Rows[0].Cells[0].Text).ToString("dd/MMM/yyyy");
LblLastLoginT.Text = GrdLasLogin.Rows[0].Cells[1].Text;
DateTime today = System.DateTime.Now.Date;
LblToday.Text = today.ToString();
LblTime.Text = System.DateTime.Now.ToLongTimeString();
objc.LoggedInUser = LblLogdInUser.Text;
objc.AccessDate = Convert.ToDateTime(LblToday.Text);
objc.AccessTime = Convert.ToDateTime(LblTime.Text);
objc.AccessStatus = "New Login";
objc.AccessFlag = 1;
int accessinfo = obj.InsertAccessInfo(objc);
}
LblFname.Visible = true;
LblAdd.Visible = true;
LblMnum.Visible = true;
LblMailID.Visible = true;
LblBGroup.Visible = true;
}
}
catch (Exception ex)
{
Response.Redirect("ERROR.aspx");
Session.Abandon();
}
}
else
{
Response.Redirect("~/Login.aspx");
}
Response.CacheControl = "no-cache";
}
The error message makes it clear that you need to supply values for the parameter FullName. So, if you aren't already doing that, then go do that. The only complication here is null values; a string can be null, but to specify that in ADO.NET you need to pass DBNull.Value; if you use null the parameter is not included. This means you end up with code like:
cmd.Parameters.AddWithValue("FullName", (object)fullName ?? DBNull.Value);
Ugly, but it works.
Alternatively, many helper utilities will do this for you. So with "dapper":
var lastAccess = conn.Query<AccessInfo>("GetLastLogin",
new { LoggedInUser = cn, FullName = fullName, /* snipped */ },
commandType: CommandType.StoredProcesdure).FirstOrDefault();
The problem is not in your SQL. It's in your calling function in asp. You are not sending the fullname parameter to SQL server correctly. Check out this question for an example on how to send parameters.
Call a stored procedure with parameter in c#

Categories