Can I create a transaction using ADO NET Entity Data Model? - c#

is it possible on the following try-catch to execute a set of statements as a transaction using ADO NET Entity Data Model?
[ValidateInput(false)]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Customer c)
{
try
{
c.Created = DateTime.Now;
c.Active = true;
c.FullName = Request.Form["FirstName"];
db.AddToCustomer(c);
db.SaveChanges();
Log log = new Log();//another entity model object
log.Created = DateTime.Now;
log.Message =
string.Format(#"A new customer was created
with customerID {0}", c.CustomerID);
db.AddToLog(log);
db.SaveChanges();
return RedirectToAction("CreateSuccess", "Customer");
}
catch
{
return View();
}
}
Any thoughts would be very appreciated.

using (var transaction = db.Connection.BeginTransaction())
{
// your code here
...
transaction.Commit();
}

Related

ASP.NET Core - How to update existing record and insert a new one at the same time using Entity Framework

In ASP.NET Core-6 Web API Entity Framework, I want the application to perform update and insert on the same model in the database at the same time.
I have this code:
public async Task<Response<string>> CreateIdentiticationAsync(CreateIdentiticationDto model)
{
var response = new Response<string>();
using (var transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
try
{
var identification = _mapper.Map<Identification>(model);
var existingIdentifications = await _dbContext.Identifications.Where(e => e.IsModified == false).ToListAsync();
foreach (var existingIdentification in existingIdentifications)
{
if (existingIdentification != null)
{
existingIdentification.IsModified = true;
_unitOfWork.UserIdentifications.Update(identification);
await _unitOfWork.Save();
}
}
Identification.IsModified = false;
Identification.Type = model.Type;
Identification.Name = model.Name;
await _unitOfWork.UserIdentifications.InsertAsync(identification);
await _unitOfWork.Save();
response.StatusCode = (int)HttpStatusCode.Created;
response.Successful = true;
response.Message = "Created Successfully!";
transaction.Complete();
return response;
}
catch (Exception ex)
{
transaction.Dispose();
response.Message = "An error occured";
response.Successful = false;
response.StatusCode = (int)HttpStatusCode.BadRequest;
return response;
}
}
}
When user wants to insert a new record, I want the application to first check the model, if no record exists it should just insert the new record.
But if it exists, it should update all the IsModified to true, and then go ahead and also insert a new record.
However, when no record exists, I was able to insert new record.
But where I have issue is that when it wants to update and insert new record, I got this error:
Violation of PRIMARY KEY constraint 'PK_identifications'. Cannot insert duplicate key in object 'dbo.identifications'. The duplicate key value is (81fe9b8d-2d9c-4d49-8f92-22afe043e327).
Note: Id is Guid and autgenerated
How do I resolve this?
Thanks
Many things to consider here, in modern EF, I would not use a unitOfWork also a transaction is not needed unless very specific cases, you should also validate the ID from your incoming model value is null since ID is supposed to be autogenerated (most likely this is the source of your error). Since I don't know the name of your PK field, I will not introduce such validation in my proposed code.
One last recommendation, avoid this code on your controller, it breaks Single Responsibility Principle. Create a layer where you perform your business tasks and call this layer from your controller.
Here is a simplified proposed code which should work, don't forget to ensure the value in the model ID is coming as null.
public async Task<Response<string>> CreateIdentiticationAsync(CreateIdentiticationDto model)
{
var response = new Response<string>();
try
{
var identification = _mapper.Map<Identification>(model);
var existingIdentifications = await _dbContext.Identifications.Where(e => e.IsModified == false).ToListAsync();
foreach (var existingIdentification in existingIdentifications)
{
existingIdentification.IsModified = true;
}
Identification.IsModified = false;
// If you already mapped this in line 6 why map those two fields again manually?
// Identification.Type = model.Type;
// Identification.Name = model.Name;
_dbContext.UpdateRange(existingIdentifications);
_dbContext.Add(identification);
await _dbContext.SaveChangesAsync();
response.StatusCode = (int)HttpStatusCode.Created;
response.Successful = true;
response.Message = "Created Successfully!";
return response;
}
catch (Exception ex)
{
transaction.Dispose();
response.Message = "An error occured";
response.Successful = false;
response.StatusCode = (int)HttpStatusCode.BadRequest;
return response;
}
}
public IActionResult Update(int? id,UpdateEmployeeVM employeeVM)
{
ViewBag.Positions = new SelectList(_context.Positions, nameof(Position.Id), nameof(Position.Name));
Employee existed=_context.Employees.Find(id);
if(existed==null) { NotFound();}
if (!_context.Positions.Any(p => p.Id == employeeVM.PositionId)) ModelState.AddModelError("PoitionId", "Choose Id right");
if (!ModelState.IsValid)
{
ViewBag.Positions = new SelectList(_context.Positions, nameof(Position.Id), nameof(Position.Name));
return View();
}
if (employeeVM.Image!=null)
{
string result = employeeVM.Image.CheckValidate("image/", 300);
if (result.Length > 0)
{
ViewBag.Positions=new SelectList(_context.Positions,nameof(Position.Id),nameof(Position.Name));
ModelState.AddModelError("Image", result);
}
existed.ImageUrl.DeleteFile(_env.WebRootPath, "assets/img");
existed.ImageUrl = employeeVM.Image.SaveFile(Path.Combine(_env.WebRootPath, "assets", "img"));
return View();
}
existed.PositionId=employeeVM.PositionId;
existed.FullName=employeeVM.FullName;
existed.ImageUrl = employeeVM.Image.SaveFile(Path.Combine(_env.WebRootPath, "assets", "img"));
_context.SaveChanges();
return RedirectToAction(nameof(Index));
}
public async Task<IActionResult> Create(CreateEmployeeVM employeeVM)
{
if (!_context.Positions.Any(p => p.Id == employeeVM.PositionId)) ModelState.AddModelError("PositionId", "bele bir position yoxdu");
if (!ModelState.IsValid)
{
ViewBag.Positions = new SelectList(_context.Positions, nameof(Position.Id), nameof(Position.Name));
return View();
}
string result = employeeVM.Image.CheckValidate(500,"image/");
if (result.Length > 0)
{
ViewBag.Positions = new SelectList(_context.Positions, nameof(Position.Id), nameof(Position.Name));
ModelState.AddModelError("Image", result);
return View();
}
Employee employee = new Employee
{
Name = employeeVM.Name,
Surname = employeeVM.Surname,
PositionId = employeeVM.PositionId,
FacebookUrl = employeeVM.FacebookUrl,
InstagramUrl = employeeVM.InstagramUrl,
TwitterUrl = employeeVM.TwitterUrl,
Salary = employeeVM.Salary,
ImageUrl = employeeVM.Image.SaveFile(Path.Combine(_env.WebRootPath, "assets", "img"))
};
await _context.Employees.AddAsync(employee);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}

New transaction is not allowed because there are other threads running in the session ASP.Net MVC

I am getting this error but I cannot understand why? It says that
A new transaction is not allowed because there are other threads running in the session.
[HttpPost]
public ActionResult UpdateMultiple(IEnumerable<int> employeesToDelete)
{
var listemployee = db.Employees.Where(x => employeesToDelete.Contains(x.ID));
foreach (var item in listemployee)
{
int itemid = item.ID;
Employee e = db.Employees.Find(itemid);
// e = db.Employees.Find(item);
db.Entry(e).State = EntityState.Modified;
db.SaveChanges();
}
return RedirectToAction("Index");
}

how to handle different scenarios in posting different data in post action asp.net mvc5

I have a long form that posts data to 2 or 3 or 4 tables, depends on what checkboxes are selected in view.
My first question: I get an error 'not all code paths return a value'
I realize that I receive this error when there's an unhandled case, but I can't catch this case. Can you please help?
My second question: Can I wrap
var s_request = new S_REQUEST { //map model properties with vm properties };
in a function to call it multiple times?
Is there any comments on how organized the code is?
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Initiate(SViewModel vm){
string selectedWorkStepAction = Request["initiationSteps"].ToString();
switch (selectedWorkStepAction)
{
case "0":
//throw error "Please select an work step action before submission!"
//stop processing. get out of action
//don't submit form
return View(vm);
case "1":
if (vm.Coordinates == true)
{
if (vm.ShareWithContractors == false)
{
using (var context = new SatelliteServicesDBContext())
{
context.Database.Log = Console.Write;
using (DbContextTransaction transaction = context.Database.BeginTransaction())
{
try
{
if (ModelState.IsValid)
{
var s_request = new S_REQUEST
{
//map required properties with coordinates properties, keep few properties null, they will be updated later
//will get written again
//version one
};
db.S_REQUEST.Add(s_request);
db.SaveChanges();
var a_form = new A_FORM
{
//map all properties except one keep it null, will be updated later
};
db.A_FORM.Add(a_form);
db.SaveChanges();
var S_Contractor = new S_CONTRACTOR
{
//reads results from ajax function
};
db.S_CONTRACTOR.Add(S_Contractor);
db.SaveChanges();
//call approve method if data is saved successfully
return View("Success");
}
return View(vm);
}
catch (Exception)
{
transaction.Rollback();
ModelState.AddModelError("SaveError", "Unable to save changes."); //TODO make sure it shows in view not YSOD
//return View(vm);
}
//return View(vm);
}
}
}
else
{
using (var context = new SatelliteServicesDBContext())
{
context.Database.Log = Console.Write;
using (DbContextTransaction transaction = context.Database.BeginTransaction())
{
try
{
if (ModelState.IsValid)
{
var s_request = new S_REQUEST
{
//map required properties with coordinates properties, keep few properties null, they will be updated later
//version one
};
db.S_REQUEST.Add(s_request);
db.SaveChanges();
var a_form = new A_FORM
{
//map all properties except one keep it null, will be updated later
};
db.A_FORM.Add(a_form);
db.SaveChanges();
//call approve method if data is saved successfully
return View("Success");
}
return View(vm);
}
catch (Exception)
{
transaction.Rollback();
ModelState.AddModelError("SaveError", "Unable to save changes."); //TODO make sure it shows in view not YSOD
//return View(vm);
}
}
}
}
}
else //Coordinates checkbox is not checked
{
if (vm.ShareWithContractors == false)
{
using (var context = new SatelliteServicesDBContext())
{
context.Database.Log = Console.Write;
using (DbContextTransaction transaction = context.Database.BeginTransaction())
{
try
{
if (ModelState.IsValid)
{
var s_request = new S_REQUEST
{
//only required properties
//version two
};
db.S_REQUEST.Add(s_request);
db.SaveChanges();
var a_form = new A_FORM
{
//map all properties except one keep it null, will be updated later
};
db.A_FORM.Add(a_form);
db.SaveChanges();
var file = new MAP
{
//reads results from ajax function 1
//map all properties
};
db.MAP.Add(file);
db.SaveChanges();
var S_Contractor = new S_CONTRACTOR
{
//reads results from ajax function 2
//map all properties
};
db.S_CONTRACTOR.Add(S_Contractor);
db.SaveChanges();
//call approve method if data is saved successfully
return View("Success");
}
return View(vm);
}
catch (Exception)
{
transaction.Rollback();
ModelState.AddModelError("SaveError", "Unable to save changes."); //TODO make sure it shows in view not YSOD
//return View(vm);
}
}
}
}
else
{
using (var context = new SatelliteServicesDBContext())
{
context.Database.Log = Console.Write;
using (DbContextTransaction transaction = context.Database.BeginTransaction())
{
try
{
if (ModelState.IsValid)
{
var s_request = new S_REQUEST
{
//only required properties
//version two
};
db.S_REQUEST.Add(s_request);
db.SaveChanges();
var a_form = new A_FORM
{
//map all properties except one keep it null, will be updated later
};
db.A_FORM.Add(a_form);
db.SaveChanges();
var file = new MAP
{
//reads results from ajax function
};
db.MAP.Add(file);
db.SaveChanges();
//call approve method if data is saved successfully
return View("Success");
}
return View(vm);
}
catch (Exception)
{
transaction.Rollback();
ModelState.AddModelError("SaveError", "Unable to save changes."); //TODO make sure it shows in view not YSOD
//return View(vm);
}
}
}
}
}
break;
case "2":
try
{
if (ModelState.IsValid)
{
var s_request = new S_REQUEST
{
//only required properties
//version two
};
db.S_REQUEST.Add(s_request);
db.SaveChanges();
//delegate method should be called if data is saved successfully
return View("Success");
}
return View(vm);
}
catch
{
ModelState.AddModelError("SaveError", "Unable to save changes.");
//TODO make sure it shows in view not YSOD
//Console.Write("check error: " + ex);
//return View(vm); //should be inside catch, right?
}
break;
case "3":
//don't save to any table
//call cancel method
return RedirectToAction("Services", "Home");
}
}

To Get the time when data is entered into database in ASP.net using c#

I want to find the time at which Data is entered into my database. I'm using SQL Server as my database.
public class OtpchangeController : Controller
{
DateTime dbTime;
// GET: Otpchange
public ActionResult Generateotp()
{
return View();
}
[HttpPost]
public ActionResult Generateotp(tblPassword obj)
{
Random r = new Random();
using (PasswordGenerationEntities db = new PasswordGenerationEntities())
{
tblPassword newObj = (from c in db.tblPasswords
where c.Username == obj.Username
select c).First();
if(newObj != null)
{
int num = r.Next();
string newOtp = num.ToString();
newObj.Otp = newOtp;
db.SaveChanges();
dbTime = DateTime.Now;
Session["Username"] = newObj.Username.ToString();
return RedirectToAction("ChangePassword");
}
}
return View();
}
public ActionResult ChangePassword()
{
return View();
}
[HttpPost]
public ActionResult ChangePassword(tblPassword obj)
{
string name = #Session["Username"].ToString();
using (PasswordGenerationEntities db = new PasswordGenerationEntities())
{
tblPassword newObj = (from c in db.tblPasswords
where c.Otp == obj.Otp && c.Username == name
select c).First();
DateTime formTime = DateTime.Now;
TimeSpan result = dbTime.Subtract(formTime);
newObj.Password = obj.Password;
db.SaveChanges();
return RedirectToAction("Success");
}
//return View();
}
public ActionResult Success()
{
return View();
}
Here I want to find difference between the time when otp is added into database and the time when that otp is entered by the user.
But dbTime comes as 01/01/2001
But formTime is correct, also I want to find the difference between those time.
It seems the code you provided is not compiling or some parts are missing.
Anyway said I would suggest checking the msdn documentation about dbContext and its features here
You can delegate the database log to a console log or another more suitable provider(log4net or a simple custom log file). Those logs contain information about database execution times.
In your case you could do :
using (PasswordGenerationEntities db = new PasswordGenerationEntities())
{
db.Database.Log = Console.Write;
tblPassword newObj = (from c in db.tblPasswords
where c.Username == obj.Username
select c).First();
if(newObj != null)
{
int num = r.Next();
string newOtp = num.ToString();
newObj.Otp = newOtp;
db.SaveChanges();
dbTime = DateTime.Now;
Session["Username"] = newObj.Username.ToString();
return RedirectToAction("ChangePassword");
}
}
Check the console ouput.
Console Database info

While inserting data into the oracle database code automatically generate value 0 for id using MVC with entity framework

While inserting data into the Oracle database code automatically generate value 0 for id using MVC with entity framework.How to solve this.
public ActionResult AddNewNode(AddNode model)
{
try
{
if (ModelState.IsValid)
{
using (Nspira_DBContext entity = new Nspira_DBContext())
{
TBL_ACCESSRIGHTS hierarchyDetail = new TBL_ACCESSRIGHTS()
{
NAME = model.NodeName,
PID = model.ParentName,
};
entity.TBL_ACCESSRIGHTS.Add(hierarchyDetail);
entity.SaveChanges();
}
return Json(new { success = true }, JsonRequestBehavior.AllowGet);
}
}
catch (Exception ex)
{
throw ex;
}
return Json(new { success = false }, JsonRequestBehavior.AllowGet);
}
My table has ID, NAME and PID column.While inserting query in the database means it generated the sequence number.While inserting data through code means It doesn't create the sequence.It fetches value as 0 automatically.How to solve this.
How to solve this.Please, anyone, help me.
if (ModelState.IsValid)
{
using (Nspira_DBContext entity = new Nspira_DBContext())
{
int objid = entity.TBL_ACCESSRIGHTS.Max(p => p.ID);
TBL_ACCESSRIGHTS hierarchyDetail = new TBL_ACCESSRIGHTS()
{
ID = objid + 1,
NAME = model.NodeName,
PID = model.ParentName,
};
entity.TBL_ACCESSRIGHTS.Add(hierarchyDetail);
entity.SaveChanges();
}
return Json(new { success = true }, JsonRequestBehavior.AllowGet);
}
}
please try this

Categories