C# LinqToSql SubmitChanges() does not update, even though PK is set - c#

I have the following code:
public int DeActivate(User entity) {
try {
using (UsersDataContext usersDC = new UsersDataContext()) {
users user = new users();
user = usersDC.users.Where(x => x.id == entity.Id).
Select(x => new users {active = x.active}).FirstOrDefault();
//user.active = entity.Active;
user.active = false;
usersDC.SubmitChanges();
return 1;
}
}
catch {
return 0;
}
}
While running an NUnit test on the method, the method returns 1, as it is supposed to do, and while de-bugging no exceptions are thrown. But, when i cross check with the DB the records have not being affected. I have tried the following: Re-created DBML file, checked for existance of PK, and checked the following sites:
MSDN question, StackOverflow question, but to no avail.

Your select statement is wrong. Try this.
public int DeActivate(User entity) {
try {
using (UsersDataContext usersDC = new UsersDataContext()) {
var user = usersDC.users.Single(x => x.id == entity.Id);
user.active = false;
usersDC.SubmitChanges();
return 1;
}
} catch {
return 0;
}
}

Related

Ef include linked table not getting updated

I have this ef method where I am using this Include and select the parent table using the Single Id for MeetingPollingId. I am sending a model to be created into the database. Its working fine for new record where I send a 0 for the MeetingPollingQuestionId but when I send a value where there is already a record I wanted it to update the data and not create a new record. Is there something else I need to change for the update to working?
public ResultStatus SaveMeetingPollingQuestion(Model.MeetingPollingQuestion mpq)
{
using (var db = new NccnEcommerceEntities())
{
using (DbContextTransaction dbTran = db.Database.BeginTransaction())
{
ResultStatus result = new ResultStatus();
try
{
var meetingPolling = db.MeetingPollings
.Include(x => x.MeetingPollingQuestions)
.Include(x => x.MeetingPollingQuestions.Select(q => q.MeetingPollingParts))
.Single(x => x.MeetingPollingId == mpq.MeetingPollingId);
var newMeetingPollingQuestion = new EFModel.MeetingPollingQuestion
{
MeetingPollingQuestionId = mpq.MeetingPollingQuestionId,
MeetingPollingId = mpq.MeetingPollingId,
MeetingPollingQuestionTypeId = mpq.MeetingPollingQuestionTypeId,
SequenceOrder = mpq.SequenceOrder,
MeetingPollingParts = mpq.MeetingPollingParts.Select(p => new EFModel.MeetingPollingPart
{
MeetingPollingPartsTypeId = p.MeetingPollingPartsTypeId,
MeetingPollingPartsValues = p.MeetingPollingPartsValues.Select(v => new EFModel.MeetingPollingPartsValue
{
QuestionValue = v.QuestionValue,
MeetingPollingPartsValuesTypeId = v.MeetingPollingPartsValuesTypeId
}).ToList()
}).ToList()
};
meetingPolling.MeetingPollingQuestions.Add(newMeetingPollingQuestion);
db.SaveChanges();
dbTran.Commit();
result.ResultCode = Convert.ToInt32(Enums.Result.Code.Success);
result.Message = "Successfully uploaded.";
}
catch (Exception e)
{
dbTran.Rollback();
result.Message = "Error Save Meeting Polling Question" + e.Message;
result.ResultCode = Convert.ToInt32(Enums.Result.Code.Error);
}
return result;
}
}
}
What you are asking for is an "Upsert" which is not supported "out of the box" by Entity Framework. Upserts are supported in other query languages like PostgreSQL, etc.
You will have to "roll your own" Upsert functionality using Entity Framework. Since you are using .Add() in your example, you are only Insert-ing data, but never updating it. To do this, you will need to check if the question id already exists.
You can do something similar to this...
// determine whether the question id exists
var mpqIdExists = db.MeetingPollings.AsNoTracking().Where(mp => mp.MeetingPollingId == mpq.MeetingPollingId && mp.MeetingPollingQuestionId == mpq.MeetingPollingQuestionId).Any();
if (mpqIdExists)
{
// update
db.Entry(meetingPolling.MeetingPollingQuestions).CurrentValues.SetValues(newMeetingPollingQuestion);
}
else
{
// insert
meetingPolling.MeetingPollingQuestions.Add(newMeetingPollingQuestion);
}
db.SaveChanges();
dbTran.Commit();
Courtesy of:
More efficient way to perform a UPSERT with EF6

How to prevent to change other column values into table while updating single column using Entity Framework?

Here i have a method in ASP.NET MVC. What i am doing is to update single column checking every column of table is not null. If null then IsModified property changing to false. I have to write statement for every column.
My Sample Method -
public int ServicesEdit(helplineservice _helplineservice)
{
int result = 0;
try
{
db.Entry(_helplineservice).State = EntityState.Modified;
if (string.IsNullOrEmpty(_helplineservice.description))
{
db.Entry(_helplineservice).Property(p => p.description).IsModified = false;
}
else
{
db.Entry(_helplineservice).Property(p => p.description).IsModified = true;
}
if (string.IsNullOrEmpty(_helplineservice.title))
{
db.Entry(_helplineservice).Property(p => p.title).IsModified = false;
}
else
{
db.Entry(_helplineservice).Property(p => p.title).IsModified = true;
}
if (string.IsNullOrEmpty(_helplineservice.contactnumber))
{
db.Entry(_helplineservice).Property(p => p.contactnumber).IsModified = false;
}
else
{
db.Entry(_helplineservice).Property(p => p.contactnumber).IsModified = true;
}
//if (string.IsNullOrEmpty(_helplineservice.active.ToString()))
//{
// db.Entry(_helplineservice).Property(p => p.active).IsModified = false;
//}
//else
//{
// db.Entry(_helplineservice).Property(p => p.active).IsModified = true;
//}
db.SaveChanges();
result = 1;
}
catch (Exception ex)
{
result = 0;
}
return result;
}
Calling Above Method -
helplineservice _helplineservice = new helplineservice();
_helplineservice.helplineid =sectionid;
_helplineservice.allowedtoapp = allow;
result = _ftwCommonMethods.ServicesEdit(_helplineservice);
This code not look logical i think. Tell me better way to do this. How Can i Update Single Column of Table by not writing this much code? Thanks in Advance.
You can avoid all of the checking by loading the entity you want to update first.
var context = new DbContext();
// Load entity via whatever Id parameter you have.
var entityToUpdate = context.Set<Type>().FirstOrDefault(x => x.Id == idToUpdate);
if(entityToUpdate != null)
{
entityToUpdate.Value1 = newValue1;
entityToUpdate.Value2 = newValue2;
context.SaveChanges();
}
Only Value1 and Value2 will be updated. All other existing values will remain unchanged.
In your case, what you are doing is creating a new empty entity, then setting its Key to something that already exists in the database. When you attach that entity to the context, EF has no choice but to assume that all the values in that entity are the new updated values. This is standard behavior for EF.

Detach Entity Collection

Well, i have a Model with a collection saving changes in a loop structure
foreach(Customer objCustomer in listCustomer)
{
try
{
db.Customer.Add(objCustomer);
db.SaveChanges();
}
catch(Exception ex)
{
db.Entry(objCustomer).State = EntityState.Detach;
}
}
When it throws me any exception in a collection related to entity, the next ones keeps throwing exceptions.
I tried to detach the entire collection but it didn't work
foreach(Customer objCustomer in listCustomer)
{
try
{
db.Customer.Add(objCustomer);
db.SaveChanges();
}
catch(Exception ex)
{
for (int i = 0; i < objCustomer.Address; i++)
{
db.Entry(objCustomer.Address[i]).State = EntityState.Detach;
}
db.Entry(objCustomer).State = EntityState.Detach;
}
}
Any suggestion?
I don't know why but it works, i used like it refers in this post
EntityCollection Clear() and Remove() methods
objCustomer.Address.ToList().ForEach(x => db.Entry(x).State = EntityState.Detached);
It is almost as i did before using "for"
Thanks anyway everyone
i thought that the exception of second code maybe has been never occurred?
In addition,your code has any transaction ?
Try this? Warning not tested!
using(var db = new Context())
{
foreach(Customer objCustomer in listCustomer)
{
var exists = db.Customer.FirstOrDefault(x => x.CustomerID == objCustomer.CustomerID;
if( exists = null)
{
db.Customer.Add(objCustomer);
}
else
{
db.Entry(objCustomer).State = EntityState.Modified;
}
db.SaveChanges();
}
}

Updating multiple records that share a many to many relationship fails

Details
I have 2 tables (Procedures, Surgeons) with a lookup table (ProcSurg) to create a many to many relationship.
scar_Requests scar_Procedures scar_ProcSurg scar_Surgeons
------------- --------------- ------------- -------------
RequestID <> ProcedureID <> ProcedureID(fk) <> SurgeonID
... RequestID SurgeonID(fk) ...
...
A single request can have multiple procedures and each procedure can have multiple surgeons.
Everything saves correctly until I have 2 procedures each that share the same Surgeon.
Error: InvalidOperationException was unhandled
The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects.
I separated out the code for saving this part of the record to try to isolate my problem..
Addprocedures is a class that contains 1 Procedure and a list of Surgeons
class Procedure
{
public scar_Procedures Procedure { get; set; }
public List<scar_Surgeons> Surgeons { get; set; }
public void RemoveSurgeon(int SurgeonID)
{
Surgeons.Remove(Surgeons.Where(x => x.SurgeonID == SurgeonID).FirstOrDefault());
}
public Procedure()
{
Surgeons = new List<scar_Surgeons>();
}
}
Saving code: using DBContext
private void SaveProcSurg()
{
using (MCASURGContext db2 = new MCASURGContext())
{
foreach (Procedure p in AddProcedures)
{
if (p.Procedure.RequestID == 0)
{
p.Procedure.RequestID = ReqID;
}
p.Procedure.scar_Surgeons.Clear();
foreach (scar_Surgeons s in p.Surgeons)
{
if (db2.ChangeTracker.Entries<scar_Surgeons>().Where(x => x.Entity.SurgeonID == s.SurgeonID).FirstOrDefault() == null)
{
db2.scar_Surgeons.Attach(s);
}
p.Procedure.scar_Surgeons.Add(s);
}
if (p.Procedure.ProcedureID == 0)
{
db2.scar_Procedures.Add(p.Procedure);
db2.Entry(p.Procedure).State = System.Data.Entity.EntityState.Added;
}
else
{
db2.scar_Procedures.Attach(p.Procedure);
db2.Entry(p.Procedure).State = System.Data.Entity.EntityState.Modified;
}
}
db2.SaveChanges();
}
}
I've tried several different ways of saving the record and this is the closest I've come to doing it correctly.
I feel like it has something to do with the way I'm attaching the surgeons to the entity and then to the procedure. Any help, idea's or suggestions on where I can find an answer would be great!
I've been searching google endlessly for over a week and I've been trying to wrap my mind around what exactly Entity Framework is doing but I'm still pretty new to this.
Edited 9/24/2013
Sorry this is the complete code snippet from the comments section with the req variable included
//Internal variable
private scar_Requests req;
private List<Procedure> AddProcedures = new List<Procedure>();
//Gets a scar_Request from the DB
private void GetRequest()
{
using (MCASURGContext db = new MCASURGContext())
{
req = db.scar_Requests.Include("scar_Procedures.scar_Surgeons").Include("scar_Status").Include("scar_Users.scar_Service").Where(x => x.RequestID == ReqID).FirstOrDefault();
foreach (scar_Procedures p in req.scar_Procedures) { AddProcedures.Add(new Procedure() { Proc = p, Surgeons = p.scar_Surgeons.ToList() }); }
}
}
Keeping with good form I'll post my answer since I think I figured it out. Maybe it will help someone in the future.
I completely re-wrote the saving and cut out a lot of useless code that I was using before and less calls to the DB. There was other methods that I didn't post above that saved other parts of the record that I condensed into a single method.
Basically I get the record and its joined tables from the DB and iterate through all the fields/joined tables that need to be updated and save it back to the DB. (Seems super obvious now but I tried this way before and I must have had something wrong because it didn't work the first few times I tried it this way.)
I don't know if its 100% correct or written up to normal coding standards and I still have some final tweaking to do before its completely done.
private void SaveProcSurg()
{
using (MCASURGContext db2 = new MCASURGContext())
{
//Get Record from DB
scar_Requests sReq = db2.scar_Requests.Include("scar_Users").Include("scar_Status").Include("scar_Procedures.scar_Surgeons").Where(x => x.RequestID == ReqID).FirstOrDefault();
//Update Record fields
sReq.CreationDate = req.CreationDate == null ? DateTime.Now : req.CreationDate = req.CreationDate;
sReq.DateOfSurgery = dtpDateOfSurgery.Value;
sReq.IsDeleted = false;
sReq.IsScheduled = false;
sReq.LatexAllergy = cbLatexAllergy.Checked;
sReq.ModifiedDate = DateTime.Now;
sReq.MRN = txtMRN.Text;
sReq.PatientName = txtPatientName.Text;
foreach (RadioButton rb in gbPatientType.Controls) if (rb.Checked == true) sReq.PatientType = rb.Text;
sReq.PreOpDiagnosis = txtPreOpDiag.Text;
sReq.PrimarySurgeon = txtPrimarySurgeon.Text;
sReq.PrivateComment = txtPrivateComment.Text;
sReq.PublicComment = txtPublicComment.Text;
sReq.RequestID = ReqID;
sReq.StatusID = req.StatusID;
sReq.UserID = req.UserID;
//Update Users/Status
sReq.scar_Users = db2.scar_Users.Where(x => x.UserID == sReq.UserID).FirstOrDefault();
sReq.scar_Status = db2.scar_Status.Where(x => x.StatusID == req.StatusID).FirstOrDefault();
//Attach to DBContext
db2.scar_Requests.Attach(sReq);
//Update Procedures
foreach (Procedure p in AddProcedures)
{
scar_Procedures pro = sReq.scar_Procedures.Where(x => x.ProcedureID == p.Proc.ProcedureID && p.Proc.ProcedureID != 0).FirstOrDefault();
if (pro != null)
{
pro.EnRecovery = p.Proc.EnRecovery;
pro.IsPrimary = p.Proc.IsPrimary;
pro.Laterality = p.Proc.Laterality;
pro.OrthoFastTrack = p.Proc.OrthoFastTrack;
pro.ProcedureID = p.Proc.ProcedureID;
pro.ProcedureText = p.Proc.ProcedureText;
pro.RequestID = ReqID;
pro.Site = p.Proc.Site;
}
else
{
pro = new scar_Procedures();
pro.EnRecovery = p.Proc.EnRecovery;
pro.IsPrimary = p.Proc.IsPrimary;
pro.Laterality = p.Proc.Laterality;
pro.OrthoFastTrack = p.Proc.OrthoFastTrack;
pro.ProcedureID = p.Proc.ProcedureID;
pro.ProcedureText = p.Proc.ProcedureText;
pro.RequestID = ReqID;
pro.Site = p.Proc.Site; ;
pro.scar_Requests = sReq;
}
//Update Surgeons
pro.scar_Surgeons.Clear();
foreach (scar_Surgeons s in p.Surgeons)
{
pro.scar_Surgeons.Add(db2.scar_Surgeons.Where(x=> x.SurgeonID == s.SurgeonID).FirstOrDefault());
}
}
//Set State and Save
db2.Entry(sReq).State = System.Data.Entity.EntityState.Modified;
db2.SaveChanges();
}
}

First method of Linq giving error

In my webmethod of my WCF rest service i am trying to find record using Linq's First method like below
[WebInvoke(UriTemplate = "UpdateProductObject", Method = "PUT")]
public Result UpdateProductObject(ProductObjectToSave prodSave)
{
IUnitOfWork unitOfWork = new UnitOfWork((IObjectContext)_objectSetFactory);
var versions = prodSave.VersionDetails;
foreach (var versionDetail in versions)
{
var detail = versionDetail;
var dbVersionentity = _productVersionEntityRepository.First(x => x.Id == detail.Id);
if (detail.Id < 0)
{
dbVersionentity.Id = GetNextTableId("vProductVersion");
}
dbVersionentity.Name = detail.Name;
dbVersionentity.Code = detail.Name;
if (detail.Id > 0){
_productVersionEntityRepository.Update(dbVersionentity);
}
else
{
_productVersionEntityRepository.Insert(dbVersionentity);
}
}
try
{
unitOfWork.Commit();
}
catch (Exception e)
{
return new Result() { Error = e.Message };
}
return new Result() { Error = "Record updated successfully" };
}
The "_productVersionEntityRepository" is defined as below in my service.
private readonly Repository<ProductVersionEntity> _productVersionEntityRepository;
When there are no records it throws exception "Sequence contains no elements" . I have done some finding that we can use FirstOrDefault method. But somehow i am not getting that option to use FirstOrDefault. I am really new to this so may be i have missed some links where solution could have been described. Please help me or suggest me other way to do some error handling if First method fails
That's the way that First() works, it will throw an exception if the element can't be found. You can use FirstorDefault() instead and check if the element is null.
Edit: I realised that you're using a custom repository. If you have access to the source code, I advise you to add a new method called .FirstOrDefault() that will take as parameter a predicate and returns null if no entities are found.
Edit 2: Add this method to your repository:
T FirstOrDefault(Expression<Func<T, bool>> where, params Expression<Func<T, object>>[] includeProperties)
{
IQueryable<T> query = AsQueryable();
query = PerformInclusions(includeProperties, query);
return query.FirstOrDefault(where);
}
Then you can do something like this in your code:
foreach (var versionDetail in versions)
{
bool isNew = false;
var detail = versionDetail;
var dbVersionentity = _productVersionEntityRepository.FirstOrDefault(x => x.Id == detail.Id);
// not found in database
if(dbVersionentity == null)
{
isNew = true;
// create entity here
dbVersionentity = new .....;
// you don't need to do this if id is auto-generated,
// i.e. Identity column in SQL Server
dbVersionentity.Id = GetNextTableId("vProductVersion");
}
dbVersionentity.Name = detail.Name;
dbVersionentity.Code = detail.Name;
if (isNew)
{
_productVersionEntityRepository.Insert(dbVersionentity);
}
else
{
_productVersionEntityRepository.Update(dbVersionentity);
}
}
try
var dbVersionentity = _productVersionEntityRepository.Where(x => x.Id == detail.Id).FirstOrDefault();

Categories

Resources