I am using EF6 with C# in Asp.net 4.5. I want to update existing entry with new entry. For example:
Customer customer = new Customer()
{
Address = txtAddress.Text,
Name = txtName.Text,
UserName = txtUserName.Text
};
if(Id==0)
{
//INSERT
customer.Password = MyHelper.md5(txtPassword.Text);
customer.CreatedDate = DateTime.Now;
db.Customers.Add(customer);
}
else
{
//UPDATE
Customer currentCustomer = db.Customers.FirstOrDefault(x => x.Id == Id);
customer.Id = Id;
if (!String.IsNullOrEmpty(txtPassword.Text))
customer.Password = MyHelper.md5(txtPassword.Text);
db.Entry(currentCustomer).CurrentValues.SetValues(customer);
}
It inserts new entry and updates Address, Name, UserName properties successfully. But in update event, it changes CreatedDate and Password fields to NULL. Because I didn't specified Password and CreatedDate fields again. I want EF to skip these fields in update. But as I understand, it assumes these fields as null.
Is it a bug, or a feature of Entity Framework. So, what should I do if I want to update an entry with another entry? Do I have to specify all values again?
This is an issue with your process. customer is an in-memory representation of a new Customer. You define .Password and .CreatedDate only when Id==0 therefore it isn't available during your update routine. And then your .SetValues(customer) declaration sets the existing currentCustomer.Password and currentCustomer.CreatedDate to null
Update your code to only update properties from customer that you wish to be updated in currentCustomer. Like so:
//UPDATE
Customer currentCustomer = db.Customers.FirstOrDefault(x => x.Id == Id);
currentCustomer.Address = customer.Address;
db.Customers.Update(currentCustomer);
For an even cleaner approach, you could revise entirely to:
Customer c;
if(Id == 0) {
c = new Customer(){
Password = MyHelper.md5(txtPassword.Text),
CreatedDate = DateTime.Now
};
}
else
c = db.Customers.FirstOrDefault(x => x.Id == Id);
if (c != null) {
c = c{
Address = txtAddress.Text,
Name = txtName.Text,
UserName = txtUserName.Text
};
if(Id != 0)
db.Customers.Update(c);
else
db.Customers.Insert(c);
db.SaveChanges();
}
Related
I have an application which keeps updating every 1 second and I need to update my database accordingly.
I have this following getOrg function which grabs the data from API endpoint and insert into the database, but before inserting it checks hash for the duplicates, till here it works really well. But the problem is if something changes there will be new hash and as its a new hash it will go ahead and try to insert record but as OrgGuid is my primary key it is giving me:
SqlException: Violation of PRIMARY KEY constraint
So my question is how can I update only those columns which got changed?
public async Task getOrg()
{
var request = new HttpRequestMessage(HttpMethod.Get, "organizations");
var response = await _client_NP.SendAsync(request);
var json = await response.Content.ReadAsStringAsync();
OrganizationsClass.OrgsRootObject model = JsonConvert.DeserializeObject<OrganizationsClass.OrgsRootObject>(json);
foreach (var item in model.resources)
{
string tmpmasterhash = HashClass.CreateMD5(item.guid + item.name + item.created_at + item.updated_at);
if (!_DBcontext.Organizations.Any(o => o.Orghash == tmpmasterhash))
{
var Orgs = new Organizations
{
OrgGuid = Guid.Parse(item.guid),
Name = item.name,
CreatedAt = item.created_at,
UpdatedAt = item.updated_at,
Orghash = tmpmasterhash,
Timestamp = DateTime.Now,
Foundation = 3
};
_DBcontext.Organizations.Add(Orgs);
}
}
await _DBcontext.SaveChangesAsync();
}
Retrieve the organization for the given Guid first, and if it exists, update it. If it doesn't exist, add it
var g = Guid.Parse(item.guid);
var x = _DBcontext.Organizations.FirstOrDefault(o => o.OrgGuid == g);
if(x == null)
_DBcontext.Organizations.Add(new Organizations
{
OrgGuid = g,
Name = item.name,
CreatedAt = item.created_at,
UpdatedAt = item.updated_at,
Orghash = tmpmasterhash,
Timestamp = DateTime.Now,
Foundation = 3
});
else{
x.Name = item.name;
.... //whatever else you want to update
}
await _DBcontext.SaveChangesAsync();
PS; if the hash changes it's not a good idea to dedupe based on it; by definition you have an ID that doesn't change, don't bother with your hash - use the Guid you use for the PK?
Per my comment, hash is really only useful to know whether you should run a DB update, but honestly, it's probably useless. I would expect that EF won't bother to save the object if you update the properties to the same values they are already so calcing a hash is a waste of time but here's how you might:
var g = Guid.Parse(item.guid);
var x = _DBcontext.Organizations.FirstOrDefault(o => o.OrgGuid == g);
if(x == null){
_DBcontext.Organizations.Add(new Organizations
{
OrgGuid = g,
Name = item.name,
CreatedAt = item.created_at,
UpdatedAt = item.updated_at,
Orghash = tmpmasterhash,
Timestamp = DateTime.Now,
Foundation = 3
});
await _DBcontext.SaveChangesAsync();
} else if(tmpmasterhash != x.Orghash) {
x.Name = item.name;
.... //whatever else you want to update
await _DBcontext.SaveChangesAsync();
}
Attach
Attaches a record to the context. This is optimistic behavior: Entity Framework expects the record to exist and only observes other records that make use of this attached record. Any modifications made to the attached record are not passed on to the database.
Read this: https://learn.microsoft.com/en-us/ef/ef6/saving/change-tracking/entity-state
Original answer: https://pt.stackoverflow.com/a/38195/14630
Button2 is the edit button, now i'm supposed to edit data that show in textboxes and press edit to change the values and save the into the database and show them in gridview aswell. But for some reason it says that newEmployee.FirstName was null, what do i do?
private void button2_Click(object sender, EventArgs e)
{
Employee Emp = SetValues(textBox1.Text, textBox2.Text, textBox3.Text);
bool result = UpdateEmployee(Emp);
ClearAll();
Display();
}
public bool UpdateEmployee (Employee Emp)
{
bool result = false;
using (var entity = new NorthwindEntities())
{
Employee newEmployee = entity.Employee.Where(x => x.EmployeeID == Emp.EmployeeID).Select(x => x).FirstOrDefault();
newEmployee.FirstName = Emp.FirstName;
newEmployee.LastName = Emp.LastName;
newEmployee.BirthDate = Emp.BirthDate;
entity.SaveChanges();
result = true;
}
return result;
}
private Employee SetValues(string FirstName, string LastName, string BirthDate)
{
Employee Emp = new Employee();
Emp.FirstName = FirstName;
Emp.LastName = LastName;
Emp.BirthDate = BirthDate;
return Emp;
}
Simple answer would be
newEmployee.FirstName = Emp.FirstName ?? string.Empty;
That said I cannot tell why Emp.FirstName is null to start with. In your code the following makes no sense either
Employee newEmployee = entity.Employee.Where(x => x.EmployeeID == Emp.EmployeeID).Select(x => x).FirstOrDefault();
since newEmployee cannot have a EmployeeID if it's new
Please check that you are getting employee or not by doing null check like as below
Employee newEmployee = entity.Employee.Where(x => x.EmployeeID ==
Emp.EmployeeID).Select(x => x).FirstOrDefault();
if(newEmployee!=null)
{
newEmployee.FirstName = Emp.FirstName;
newEmployee.LastName = Emp.LastName;
newEmployee.BirthDate = Emp.BirthDate;
entity.SaveChanges();
result = true;
}
I think you are getting error because FirstOrDefault returning null value , which is you are not checking
Instead of FirstOrDefault you must make use of SingleOrDefault as only one employee going to map with one ID, because Id i think in most of the cases it primary value . and you are not going to get more than one record i.e. you will receive single record only.
you forgot to set status of entity to modified state :EntityState.Modified
using (var context = new BloggingContext())
{
//set stus to modified
context.Entry(existingBlog).State = EntityState.Modified;
// Do some more work...
context.SaveChanges();
}
I am new to entity framework and LINQ. I am stuck at an issue where I need to firstly check if the record already exists, if it exists then I need to update the record with column RESUMEID accordingly. If not then I need to add the record. I am able to add successfully but I don't know how to update the record in LINQ.
Below is my attempt:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ReferralViewModel viewModel)
{
var candidateId = User.Identity.GetUserId();
// I AM CONFUSED ABOUT BELOW STATEMENT
var IsDupeReferral = _context.Referrals
.Where(r => (r.CandidateId == candidateId)
&& (r.CompanyId == viewModel.CompanyId) && (r.SkillId == viewModel.SkillId))
.Select(r=>r.ReferralId).SingleOrDefault();
if(IsDupeReferral!=0)
{
//IF I FIND DUPE REFERRAL RECORD I WANT TO UPDATE SOME OF THE VALUES IN THAT
_context.Referrals.Where(r => r.ReferralId == IsDupeReferral).
AND UPDATE r.resumeId with viewModel.ResumeId // How to do this?
// NOT SURE ABOUT BELOW LINE EITHER
_context.SaveChanges();
}
else
{
// BELOW CODE IS WORKING FINE
var referral = new Referral
{
ReferralName = viewModel.ReferralName,
ResumeId = viewModel.ResumeId,
CandidateId = candidateId,
DegreeId = viewModel.DegreeId,
CoverLetterId = viewModel.CoverLetterId,
SkillId = viewModel.SkillId
};
if (!string.IsNullOrEmpty(viewModel.TempCompany))
{
var newCompany = new Company
{
CompanyName = viewModel.TempCompany
};
newCompany.Referrals.Add(referral);
_context.Companies.Add(newCompany); ;
}
else
{
referral.CompanyId = viewModel.CompanyId.Value;
_context.Referrals.Add(referral);
}
_context.SaveChanges();
}
return RedirectToAction("ReferralCenter");
}
Here's the solution
//IF I FIND DUPE REFERRAL RECORD I WANT TO UPDATE SOME OF THE VALUES IN THAT
var referral = _context.Referrals.FirstOrDefault(r => r.ReferralId == IsDupeReferral);
// AND UPDATE r.resumeId with viewModel.ResumeId
if (referral !=null) {
referral.resumeId = viewModel.ResumeId;
_context.Entry(referral).State = System.Data.EntityState.Modified;
_context.SaveChanges();
}
Actually, you don't need getting the IsDupeReferral and then request the record again. Try to combine your code as the following:
var referral = _context.Referrals
.Where(r => (r.CandidateId == candidateId)
&& (r.CompanyId == viewModel.CompanyId) && (r.SkillId == viewModel.SkillId)).SingleOrDefault();
if (referral !=null) {
referral.resumeId = viewModel.ResumeId;
_context.Entry(referral).State = System.Data.EntityState.Modified;
_context.SaveChanges();
}
else {
// add a new record
}
Referral referral = _context.Referrals.FirstOrDefault(r=> r.ReferralId = SomeId);
if(referral == null) // then referral does not exist - add it
{
referral = new Referral{
ReferralName = viewModel.ReferralName,
ResumeId = viewModel.ResumeId,
CandidateId = candidateId,
DegreeId = viewModel.DegreeId,
CoverLetterId = viewModel.CoverLetterId,
SkillId = viewModel.SkillId
};
_context.Referrals.Add(referral);
}
else // referral already exists - update its values
{
//make changes to referral
referral.ReferralName = viewModel.ReferralName;
referral.ResumeId = viewModel.ResumeId;
referral.CandidateId = candidateId;
referral.DegreeId = viewModel.DegreeId;
referral.CoverLetterId = viewModel.CoverLetterId;
referral.SkillId = viewModel.SkillId;
}
_context.SaveChanges(); //no matter added or updated - save the changes
I'm somewhat new to EF 6.0 so I'm pretty sure I'm doing something wrong here.
there are two questions related to the problem
what am I doing wrong here
what's the best practice to achieve this
I'm using a code first model, and used the edmx designer to design the model and relationships, the system needs to pull information periodically from a webservice and save it to a local database (SQL Lite) in a desktop application
so I get an order list from the API, when I populate and try to save Ticket, I get a duplicate key exception when trying to insert TicketSeatType -
how do I insert the ticket to dbContext, so that It doesn't try and re-insert insert TicketSeatType and TicketPriceType, I have tried setting the child object states to unchanged but it seems to be inserting
secondly, what would be the best practice to achieve this using EF ? it just looks very inefficient loading each object into memory and comparing if it exists or not
since I need to update the listing periodically, I have to check against each object in the database if it exists, then update, else insert
code:
//read session from db
if (logger.IsDebugEnabled) logger.Debug("reading session from db");
dbSession = dbContext.SessionSet.Where(x => x.Id == sessionId).FirstOrDefault();
//populate orders
List<Order> orders = (from e in ordersList
select new Order {
Id = e.OrderId,
CallCentreNotes = e.CallCentreNotes,
DoorEntryCount = e.DoorEntryCount,
DoorEntryTime = e.DoorEntryTime,
OrderDate = e.OrderDate,
SpecialInstructions = e.SpecialInstructions,
TotalValue = e.TotalValue,
//populate parent refernece
Session = dbSession
}).ToList();
//check and save order
foreach (var o in orders) {
dbOrder = dbContext.OrderSet.Where(x => x.Id == o.Id).FirstOrDefault();
if (dbOrder != null) {
dbContext.Entry(dbOrder).CurrentValues.SetValues(o);
dbContext.Entry(dbOrder).State = EntityState.Modified;
}
else {
dbContext.OrderSet.Add(o);
dbContext.Entry(o.Session).State = EntityState.Unchanged;
}
}
dbContext.SaveChanges();
//check and add ticket seat type
foreach (var o in ordersList) {
foreach (var t in o.Tickets) {
var ticketSeatType = new TicketSeatType {
Id = t.TicketSeatType.TicketSeatTypeId,
Description = t.TicketSeatType.Description
};
dbTicketSeatType = dbContext.TicketSeatTypeSet.Where(x => x.Id == ticketSeatType.Id).FirstOrDefault();
if (dbTicketSeatType != null) {
dbContext.Entry(dbTicketSeatType).CurrentValues.SetValues(ticketSeatType);
dbContext.Entry(dbTicketSeatType).State = EntityState.Modified;
}
else {
if (!dbContext.ChangeTracker.Entries<TicketSeatType>().Any(x => x.Entity.Id == ticketSeatType.Id)) {
dbContext.TicketSeatTypeSet.Add(ticketSeatType);
}
}
}
}
dbContext.SaveChanges();
//check and add ticket price type
foreach (var o in ordersList) {
foreach (var t in o.Tickets) {
var ticketPriceType = new TicketPriceType {
Id = t.TicketPriceType.TicketPriceTypeId,
SeatCount = t.TicketPriceType.SeatCount,
Description = t.TicketPriceType.Description
};
dbTicketPriceType = dbContext.TicketPriceTypeSet.Where(x => x.Id == ticketPriceType.Id).FirstOrDefault();
if (dbTicketPriceType != null) {
dbContext.Entry(dbTicketPriceType).CurrentValues.SetValues(ticketPriceType);
dbContext.Entry(dbTicketPriceType).State = EntityState.Modified;
}
else {
if (!dbContext.ChangeTracker.Entries<TicketPriceType>().Any(x => x.Entity.Id == ticketPriceType.Id)) {
dbContext.TicketPriceTypeSet.Add(ticketPriceType);
}
}
}
}
dbContext.SaveChanges();
//check and add tickets
foreach (var o in ordersList) {
dbOrder = dbContext.OrderSet.Where(x => x.Id == o.OrderId).FirstOrDefault();
foreach (var t in o.Tickets) {
var ticket = new Ticket {
Id = t.TicketId,
Quantity = t.Quantity,
TicketPrice = t.TicketPrice,
TicketPriceType = new TicketPriceType {
Id = t.TicketPriceType.TicketPriceTypeId,
Description = t.TicketPriceType.Description,
SeatCount = t.TicketPriceType.SeatCount,
},
TicketSeatType = new TicketSeatType {
Id = t.TicketSeatType.TicketSeatTypeId,
Description = t.TicketSeatType.Description
},
Order = dbOrder
};
//check from db
dbTicket = dbContext.TicketSet.Where(x => x.Id == t.TicketId).FirstOrDefault();
dbTicketSeatType = dbContext.TicketSeatTypeSet.Where(x => x.Id == t.TicketSeatType.TicketSeatTypeId).FirstOrDefault();
dbTicketPriceType = dbContext.TicketPriceTypeSet.Where(x => x.Id == t.TicketPriceType.TicketPriceTypeId).FirstOrDefault();
if (dbTicket != null) {
dbContext.Entry(dbTicket).CurrentValues.SetValues(t);
dbContext.Entry(dbTicket).State = EntityState.Modified;
dbContext.Entry(dbTicket.Order).State = EntityState.Unchanged;
dbContext.Entry(dbTicketSeatType).State = EntityState.Unchanged;
dbContext.Entry(dbTicketPriceType).State = EntityState.Unchanged;
}
else {
dbContext.TicketSet.Add(ticket);
dbContext.Entry(ticket.Order).State = EntityState.Unchanged;
dbContext.Entry(ticket.TicketSeatType).State = EntityState.Unchanged;
dbContext.Entry(ticket.TicketPriceType).State = EntityState.Unchanged;
}
}
}
dbContext.SaveChanges();
UPDATE:
Found the answer, it has to do with how EF tracks references to objects, in the above code, I was creating new entity types from the list for TicketPriceType and TicketSeatType:
foreach (var o in ordersList) {
dbOrder = dbContext.OrderSet.Where(x => x.Id == o.OrderId).FirstOrDefault();
foreach (var t in o.Tickets) {
var ticket = new Ticket {
Id = t.TicketId,
Quantity = t.Quantity,
TicketPrice = t.TicketPrice,
TicketPriceType = new TicketPriceType {
Id = t.TicketPriceType.TicketPriceTypeId,
Description = t.TicketPriceType.Description,
SeatCount = t.TicketPriceType.SeatCount,
},
TicketSeatType = new TicketSeatType {
Id = t.TicketSeatType.TicketSeatTypeId,
Description = t.TicketSeatType.Description
},
Order = dbOrder
};
....
in this case the EF wouldn't know which objects they were and try to insert them.
the solution is to read the entities from database and allocate those, so it's referencing the same entities and doesn't add new ones
foreach (var t in o.Tickets) {
//check from db
dbTicket = dbContext.TicketSet.Where(x => x.Id == t.TicketId).FirstOrDefault();
dbTicketSeatType = dbContext.TicketSeatTypeSet.Where(x => x.Id == t.TicketSeatType.TicketSeatTypeId).FirstOrDefault();
dbTicketPriceType = dbContext.TicketPriceTypeSet.Where(x => x.Id == t.TicketPriceType.TicketPriceTypeId).FirstOrDefault();
var ticket = new Ticket {
Id = t.TicketId,
Quantity = t.Quantity,
TicketPrice = t.TicketPrice,
TicketPriceType = dbTicketPriceType,
TicketSeatType = dbTicketSeatType,
Order = dbOrder
};
...}
Don't you think that you are trying to write very similar codes for defining the state of each entity?
We can handle all of these operations with a single command.
You can easily achieve this with the newly released EntityGraphOperations for Entity Framework Code First. I am the author of this product. And I have published it in the github, code-project (includes a step-by-step demonstration and a sample project is ready for downloading) and nuget. With the help of InsertOrUpdateGraph method, it will automatically set your entities as Added or Modified. And with the help of DeleteMissingEntities method, you can delete those entities which exists in the database, but not in the current collection.
// This will set the state of the main entity and all of it's navigational
// properties as `Added` or `Modified`.
context.InsertOrUpdateGraph(ticket);
By the way, I feel the need to mention that this wouldn't be the most efficient way of course. The general idea is to get the desired entity from the database and define the state of the entity. It would be as efficient as possible.
I am trying write LINQ to Add or Update but for me EntityState.Modified is not working.
Have a look at my code and let me know if you see any error.
Only new record insert works but Update does not work.
I am using EF 6.0.
dbContext _context = new dbContext();
string userName = //getting this value from somewhere else;
string userRoleNo = //getting this value from somewhere else;
Student student = new Student
{
userName = userName,
userRoleNo = userRoleNo,
Date = DateTime.Now
};
bool exist = _context.Students.Any(x => x.UserId == new Guid(userId));
if (exist)
_context.Entry(Student).State = EntityState.Modified;
else
_context.Students.Add(student);
_context.SaveChanges();
I guess it should be
db.Entry(student).State = EntityState.Modified
and not
db.Entry(Student).State = EntityState.Modified
The correct way of doing this will be
using(_context = new dbContext()){ //This will dispose the context
string userName = //getting this value from somewhere else;
string userRoleNo = //getting this value from somewhere else;
Student student = _context.Students.FirstOrDefault(x => x.UserId == new Guid(userId));
if (student != null)
{
student.userName = userName;
student.userRoleNo = userRoleNo;
student.Date = DateTime.Now ;
_context.Entry(student).State = EntityState.Modified;
}
else
{
student = new Student () {
userName = userName,
userRoleNo = userRoleNo,
Date = DateTime.Now
};
_context.Students.Add(student);
}
_context.SaveChanges();
};
Only add if it's a new student. If not, EF will track the changes for you. This way you can leave the tracking and attaching to EF.
dbContext _context = new dbContext();
var student = _context.Students.FirstOrDefault(x => x.UserId == new Guid(userId)); // Get the existing student.
bool exists = true;
if(student == null){
student = new Student();
exists = false;
}
string userName = //getting this value from somewhere else;
string userRoleNo = //getting this value from somewhere else;
student.userName = userName; // Do you really want to reset this?
student.userRoleNo = userRoleNo;
student.Date = DateTime.Now:
if(!exists){
_context.Students.Add(student);
}
_context.SaveChanges();
Attach and EntityState.Modified is only needed when you don't fetch the item from the context. But in this case it will work to fetch the item instead.