Can't Update database with Entity Framework Core - c#

I'm learning asp.net WebApi and EFCore (CodeFirst) and as an exercise, I'm building Warehouse Api and my update method doesn't work.
This is my repository code:
public void Update(T toUpdate)
{
if(toUpdate == null) throw new ArgumentNullException("Entity is null");
T tmp = GetById(toUpdate.Id);
tmp = toUpdate;
_context.SaveChanges();
}
and this is my Service code:
public void UpdateEmployee(UpdateEmployeeCommand command)
{
UpdateEmployeeCommandValidator validator = new UpdateEmployeeCommandValidator();
var results = validator.Validate(command);
if (!results.IsValid)
{
throw new CommandValidationException(results.Errors.Select(x => new CommandValidationError
{
ErrorCode = x.ErrorCode,
ErrorMessage = x.ErrorMessage,
PropertyName = x.PropertyName
}));
}
_repository.Update(new Employee()
{
Id = command.Id,
FirstName = command.FirstName,
Address = command.Address,
LastName = command.LastName,
Age = command.Age,
Email = command.Email,
PhoneNumber = command.PhoneNumber
});
}
and this is how I use it in Controller:
public ActionResult UpdateEmployee(int Id, UpdateEmployeeCommand command)
{
if(Id != command.Id)
{
return BadRequest();
}
var employeeModelFromRepo = _repository.GetById(Id);
if(employeeModelFromRepo == null)
{
return NotFound();
}
_employeeService.UpdateEmployee(command);
return NoContent();
}
When I call UpdateEmployee, it runs without any error but it doesn't update my database.
I'm new to this, so this might be an easy fix.

I am using this generic update function:
public virtual T Update(T t) where T : class, IBaseEntity // contains Id as primary key
{
if (t == null)
return null;
var exist = Context.Set<T>().Find(t);
// Or you can try
var exist = Context.Set<T>()
.Where(i=>i.Id=t.Id).FirstOrdDefault();
if (exist == null) return exist;
Context.Entry(exist).CurrentValues.SetValues(t);
Context.SaveChanges();
return exist;
}

Don't you forget to call your service method in the controller end-point? UpdateEmployee()

Commented solution works, i just had to add db.Entry(tmp).CurrentValues.SetValues(toUpdate) to the repository code.

Related

Business logic in ASP.NET Core MVC

This is my first question here so I'm really open for opinions, I searched a lot about ASP.NET Core MVC and still I don't have enough answers if I'm writing code in right way.
In many tutorials on Youtube I saw people create ASP.NET Core MVC applications with CRUD operations but there were just simple without any logic and all code was in controllers.
What if I want add some logic for example checking if my record already exists in the database? Where should I put this?
I have class Patient and I want add patient to database so I got in patient controller this :
public async Task<IActionResult> Create([Bind("PatientId,Name,Surname,Pesel")] Patient patient)
{
if (ModelState.IsValid)
{
String result = facade.Add_patient(patient);
if (result == "Patient added")
{
_context.Add(patient);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
else
{
ViewBag.Message = "Patient exists";
return View();
}
}
}
Facade is my class in model folder where I have this :
public class Facade
{
private Database_controller _context;
public Facade(Database_controller context)
{
_context = context;
}
private List<Patient> patients = new List<Patient>();
public List<Patient> Patients { get => patients; set => patients = value; }
public void updatedata()
{
patients = _context.Patients.ToList();
}
public string Add_patient(Patient patient)
{
Patient Patient = new Patient();
Patient.Name = patient.Name;
Patient.Surname = patient.Surname;
Patient.Pesel = patient.Pesel;
String if_is = addpacjent(Patient);
if (!"Is".Equals(if_is))
{
return "Patient added";
}
else
{
return "Patient exists";
}
}
public String addpacjent(Patient val)
{
bool if_is = patients.Contains(val);
if (if_is == true)
{
return ("Is");
}
else
{
patients.Add(val);
return null;
}
}
}
In Patient class is override method equals for checking
public override bool Equals(Object ob)
{
String Name = Surname;
String Name2 = ((Patient)ob).Surname;
String Pesel1 = Pesel;
String Pesel2 = ((Patient)ob).Pesel;
bool a = Name.Equals(Name2);
if (Pesel2 != "0")
{
bool b = Pesel1.Equals(Pesel2);
bool c = false;
if (a && b == true)
{
c = true;
}
return c;
}
else
return a;
}
Is it the right way? Should I have method _context.Add(patient) in Facade or controller? Where should I check existence in database?
I already have application which I want write in .NET Core in Winforms so I want use as many as possible code from Winforms classes so it's why I started coding like this in ASP.NET Core MVC
The easiest way is to use Any(),this is because Any() will return as soon as it finds a match.
Like my following:
public IActionResult Test()
{
//Simulation data:
var patient = new Patient
{
Name="AA",
SumName="AA-aa",
Pesel="23"
};
//Here you can add your conditions.
if (!_context.Patients.Any(o => o.Name == patient.Name&&o.SumName==patient.SumName&&o.Pesel==patient.Pesel))
{
_context.Add(patient);
_context.SaveChanges();
return RedirectToAction(nameof(Index));
}
else
{
ViewBag.Message = "Patient exists";
return View();
};
}
Below is the demo data in my database:
Sample effect display:

writing update function to check before adding data in C#

hi I want to write an update function to check the data in my database and if there was a similar column don't add the filed update that filed
here in the code below, I deserialize JSON file
public class CustomerDeserializer
{
public static List<DtoCustomer> Deserialize()
{
List<DtoCustomer> result =
JsonConvert.DeserializeObject<List<DtoCustomer>>(
File.ReadAllText(#"Information.json"));
return result;
}
}
in this part, I read the data and build it
public static Customer CustomerBuild(DtoCustomer dto)
{
return new Customer()
{
FirstName = dto.FirstName,
LastName = dto.LastName,
Address = dto.Address,
Email = dto.Email,
ComapnyName = dto.CompanyName,
PhoneNumber = dto.Phone
};
and then I process data and save them into database
////update function
public static void Process(Customer customer)
{
using (var context = new PracticeEntities1())
{
context.Customers.Add(customer);
context.SaveChanges();
}
}
I want to write an update function before saving to check the data and update it what should I do?
You may do something like this:
using (var context = new PracticeEntities1())
{
var existingCustomer = context.Customers.FirstOrDefault(c => c.Email == customer.Email);
if (existingCustomer != null) {
existingCustomer.FirstName = customer.FirstName;
existingCustomer.LastName = customer.LastName;
existingCustomer.Address = customer.Address;
existingCustomer.CompanyName = customer.CompanyName;
existingCustomer.Phone = customer.Phone;
}
else
{
context.Customers.Add(customer);
}
context.SaveChanges();
}

Populate seperate table without relationship in EF Core

I need to add a picture and store the picture Id and product Id in a seperate productPicture table. You can't add a picture without an existing product. How to achieve this?
This is my code for adding an entity to database:
controller:
[HttpPost]
[Route("api/v1/catalog/products/pictures")]
[ProducesResponseType((int)HttpStatusCode.Created)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
public async Task<IActionResult> UploadPicture([FromForm]PictureViewModel pic)
{
try
{
var result = await _service.Add(pic);
if (result.HasErrors)
{
return BadRequest(result.Errors);
}
return CreatedAtAction(nameof(GetById), result);
}
catch (Exception ex)
{
return BadRequest(ex.ToString());
}
}
service:
public async Task<ServiceResultWithoutBaseEntity<Picture>> Add(PictureViewModel newItem)
{
var result = new ServiceResultWithoutBaseEntity<Picture>();
result.Errors.AddRange(Validate(newItem));
if (result.HasErrors)
return result;
var item = await newItem.MapToEntity(new Picture());
_context.Pictures.Add(item);
await _context.SaveChangesAsync();
result.EntityResult = item;
return result;
}
helper:
public async static Task<Picture> MapToEntity(this PictureViewModel source, Picture entity)
{
if (source == null || entity == null)
return null;
if (source.FileForUpload != null || source.FileForUpload.Length != 0)
{
AzureBlobExtensions abe = new AzureBlobExtensions();
string folderValue = string.Concat(entity.ID.ToString().ToLower(), "/", DateTime.Now.ToString("yyyyMMddHHmmss"), source.FileForUpload.FileName);
var fileUrl = await abe.UploadFile(source.FileForUpload, folderValue, Path.GetExtension(source.FileForUpload.FileName), "Picture");
entity.VirtualPath = fileUrl;
}
else
{
entity.VirtualPath = source.FileUrl;
}
entity.FileName = source.FileName;
entity.SeoFilename = source.SeoFilename;
entity.AltAttribute = source.AltAttribute;
entity.TitleAtrribute = source.TitleAtrribute;
entity.MimeType = source.MimeType;
entity.IsNew = source.IsNew;
return entity;
}
product table
picture table
productPicture table

Making a method more generic ASP MVC

I have an Index Method in my FileController that can return a file that is stored in the Attachments entity. How can I change the method to work with any entity not just the Attachments?
public class FileController : Controller
{
private MainDatabaseContext db = new MainDatabaseContext();
// GET: File
public ActionResult Index(int id)
{
var fileToRetrieve = db.Attachments.Find(id);
var FileObject= File (fileToRetrieve.AttachmentObject, fileToRetrieve.ContentType);
if (FileObject.FileDownloadName.Length == 0)
{
FileObject.FileDownloadName = fileToRetrieve.Filename;
}
return FileObject;
}
}
This is what I have done as a workaround, but it has a lot of repeated code which I wanted to avoid:
public class FileController : Controller
{
private MainDatabaseContext db = new MainDatabaseContext();
enum EntityName
{
Attachment=1,
WAProgramApplicationId,
HouseholdIncome,
HouseholdMember
}
// GET: File
public ActionResult Index(int id=0,int WAProgramApplicationId=0,int householdIncomeID=0,int householdMemberId=0)
{
if (householdIncomeID!=0)
{
return GetFileObject(householdIncomeID, EntityName.HouseholdIncome);
}
if (id!=0)
{
return GetFileObject(id, EntityName.Attachment);
}
if (WAProgramApplicationId != 0)
{
return GetFileObject(WAProgramApplicationId, EntityName.WAProgramApplicationId);
}
if (householdMemberId!=0)
{
return GetFileObject(householdMemberId, EntityName.HouseholdMember);
}
return null;
}
private ActionResult GetFileObject(int id, EntityName entityName)
{
if (entityName==EntityName.Attachment)
{
var fileToRetrieve = db.Attachments.Find(id);
var FileObject = File(fileToRetrieve.AttachmentObject, fileToRetrieve.ContentType);
if (FileObject.FileDownloadName.Length == 0)
{
FileObject.FileDownloadName = fileToRetrieve.Filename;
}
return FileObject;
}
if (entityName == EntityName.HouseholdIncome)
{
var fileToRetrieve = db.HouseholdIncomes.Find(id);
var FileObject = File(fileToRetrieve.AttachmentObject, fileToRetrieve.ContentType);
if (FileObject.FileDownloadName.Length == 0)
{
FileObject.FileDownloadName = fileToRetrieve.Filename;
}
return FileObject;
}
if (entityName==EntityName.WAProgramApplicationId)
{
var fileToRetrieve = db.WAProgramApplications.Find(id);
var FileObject = File(fileToRetrieve.AttachmentObject, fileToRetrieve.ContentType);
if (FileObject.FileDownloadName.Length == 0)
{
FileObject.FileDownloadName = fileToRetrieve.Filename;
}
return FileObject;
}
if (entityName==EntityName.HouseholdMember)
{
var fileToRetrieve = db.HouseholdMembers.Find(id);
var FileObject = File(fileToRetrieve.AttachmentObject, fileToRetrieve.ContentType);
if (FileObject.FileDownloadName.Length == 0)
{
FileObject.FileDownloadName = fileToRetrieve.Filename;
}
return FileObject;
}
return null;
}
}
to make the entity more generic just use the Set method, you can do it like this:
db.Set<YourEntity>().Find(id);
They are some approaches how to implement a generic controller with data.
Check here and here.
If you have a repository that can handle _repository.get<T> and return the right object, you can achieve this.

ASP.net MVC Sharing methods

I have two methods that use different viewmodels but are the same logic. At the moment I have copied and pasted them into their respective controllers. Any way to share these methods somehow?
Song Controller:
public JsonResult IncrementViews(int id)
{
using (ApplicationDbContext db = new ApplicationDbContext())
{
PublishedSongViewModel song = db.PublishedSongs.Single(x => x.Id == id);
song.UniquePlayCounts++;
db.SaveChanges();
return Json(new { UniquePlayCounts = song.UniquePlayCounts }, JsonRequestBehavior.AllowGet);
}
}
Station Controller:
public JsonResult IncrementViews(int id)
{
using (ApplicationDbContext db = new ApplicationDbContext())
{
RadioStationViewModel station = db.RadioStations.Single(x => x.Id == id);
station.UniquePlayCounts++;
db.SaveChanges();
return Json(new { UniquePlayCounts = station.UniquePlayCounts }, JsonRequestBehavior.AllowGet);
}
}
Edit:
class so far:
public static IEnumerable<Type> GetElements(ApplicationDbContext db, Type type)
{
if (type == typeof(SongsController))
return (IEnumerable<Type>)db.PublishedSongs;
else if (type == typeof(RadioStationsController))
return (IEnumerable<Type>)db.RadioStations;
else
throw new Exception("Controller not found, DBHelper");
}
Create a class called BasicController and add the method to it, like this:
public class BasicController {
public JsonResult IncrementViews(int id)
{
using (ApplicationDbContext db = new ApplicationDbContext())
{
var element = DBHelper.GetElements(db, this.GetType()).Single(x => x.Id == id);
element.UniquePlayCounts++;
db.SaveChanges();
return Json(new { UniquePlayCounts = song.UniquePlayCounts }, JsonRequestBehavior.AllowGet);
}
}
}
and modify your classes to inherit from BasicController. You will also have to create the DBHelper class with the GetElements method, which gathers the IEnumerable elements from db based on type.
EDIT: This is how you can create a helper:
public class DBHelper {
public static IEnumerable GetElements(ApplicationDbContext db, System.Type type) {
if (type == typeof(SongController)) {
return db.PublishedSongs;
} else if (type == typeof(StationController)) {
return db.RadioStations;
}
}
}

Categories