Can't save record using Entity Framework - c#

My objects will not save no matter what I do they will fetch and get info and make a new record but not update.
This is the code that details with getting existing patient and then modifying the record setting the state then calling save change this is cracking my head the last three hours what is going wrong. I was told you had to change the entity state of an object before it would no if to save but when i try to attach it it says its already attached
Appointment _appointment = new Appointment();
int errorCount = 0;
Patient _patient = SourceDal.getPatientByPatientNewId(Convert.ToInt32(txtPatientId.Text));
_patient.SSN = txtSSN.Text;
_patient.FirstName = txtPatientFirstName.Text;
_patient.LastName = txtPatientLastName.Text;
_patient.Middle = txtPatientMiddle.Text;
_patient.AddressOne = txtPatientAddressOne.Text;
_patient.City = txtPatientCity.Text;
_patient.State = txtPatientState.Text;
_patient.ZipCode = txtPatientZip.Text;
_patient.HomePhone = txtPatientHomePhone.Text;
_patient.WorkPhone = txtPatientWorkPhone.Text;
_patient.CellPhone = txtPatientCellPhone.Text;
if (rBtnHomePhone.Checked == true)
// _patient.ApptPhone = txtPatientHomePhone.Text;
if (rBtnHomePhone.Checked == true)
// _patient.ApptPhone = txtPatientHomePhone.Text;
if (rBtnWorkPhone.Checked == true)
// _patient.ApptPhone = txtPatientWorkPhone.Text;
_patient.BirthDate = dtBirthDate.DateTime;
_patient.emailAddress = txtPatientEmail.Text;
_patient.Race = Convert.ToInt32(dpRace.SelectedValue);
_patient.Ethnicity =Convert.ToInt32(dpEthnicity.SelectedValue);
_patient.Language = Convert.ToInt32(dpLanguages.SelectedValue);
if (dpGender.Text == "")
{
dpGender.Focus();
errorCount = 1;
lblGenderRequired.Text = "* Gender is required.";
}
else
{
errorCount = 0;
lblGenderRequired.Visible = false;
}
_patient.Gender = "M";
_patient.PatientID = txtPatientId.Text;
SourceDal.SourceEntities.Patients.Attach(_patient);
SourceDal.SourceEntities.Patients.Context.ObjectStateManager.ChangeObjectState(_patient, EntityState.Modified);
SourceDal.SourceEntities.SaveChanges();
The error I get is
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Data.Entity.dll
Additional information: An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
Edit 2:
Code to show my function getPaitnetByPatineyNewId
public Patient getPatientByPatientNewId(int newId)
{
Patient patient = new Patient();
if (newId == -1)
{
patient = new Patient();
}
else
{
patient = SourceEntities.Patients
.Where(w => w.ID == newId)
.FirstOrDefault();
}
return patient;
}

I think you have some issues with proper separation of concerns within your DAL, but for the short solution, you should only add (and not attach) if it's a new entity
if (_patent.PatentId == 0)
{
_patient.PatientID = txtPatientId.Text; // If you're using an identity column, remove this line. I would also strongly suggest not letting the user change this...
SourceDal.SourceEntities.Patients.Add(_patient);
}

For Anyone else the above scenarios did not work for me so this is what I had to do. I put a flag on my forms isUpdate and check that on the save button then if save call similar to below then if add just call savechanges and its now working thank you for everyone help hope this help someone.
public void SaveProviders(Provider _providers)
{
try
{
using (var ctx = new SMBASchedulerEntities(this.Connectionstring))
{
ctx.Providers.Add(_providers);
ctx.Entry(_providers).State = System.Data.Entity.EntityState.Modified;
ctx.SaveChanges();
}
}
catch (DbEntityValidationException e)
{
foreach (var eve in e.EntityValidationErrors)
{
Console.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
eve.Entry.Entity.GetType().Name, eve.Entry.State);
foreach (var ve in eve.ValidationErrors)
{
Console.WriteLine("- Property: \"{0}\", Error: \"{1}\"",
ve.PropertyName, ve.ErrorMessage);
}
}
throw;
}
}

Related

SaveChanges not working on JsonResult method (UPDATE INFO)

The problem is basically the Save changes method is not working (updating), the method should receive 3 parameters, item id, user id and the object which contains the updated information from the UI, however the code seems to be something bad because the saveChanges() method is not working.
This is my code:
[HttpPost]
[AllowAnonymous]
public JsonResult UpdatePersonalData(int ItemId, int UserId, CND_PersonalData Item)
{
try
{
if (ModelState.IsValid)
{
using (var context = new DexusEntities())
{
CND_PersonalData PersonalData = context.CND_PersonalData.Where(d => d.Id == ItemId && d.UserId == UserId).SingleOrDefault();
if (PersonalData == null)
{
/// Display bad request
/// User does not exist and/or is not activated
List<RootObject> rootObj = new List<RootObject>();
rootObj.Add(new RootObject
{
msg = "User/Item not found in our DB",
code = "error_07"
});
HttpContext.Response.StatusCode = 404;
HttpContext.Response.TrySkipIisCustomErrors = true;
JsonRes.Message = rootObj;
return Json(JsonRes, JsonRequestBehavior.AllowGet);
}
else
{
PersonalData = Item;
context.SaveChanges();
context.ChangeTracker.DetectChanges();
List<RootObject> rootObj = new List<RootObject>();
rootObj.Add(new RootObject
{
msg = "Information stored/updated successfully",
code = "success_05"
});
HttpContext.Response.StatusCode = 200;
JsonRes.Message = rootObj;
return Json(JsonRes, JsonRequestBehavior.AllowGet);
}
}
}
else
{
List<RootObject> rootObj = new List<RootObject>();
JsonRes.Issue = "The model is not correct";
rootObj.Add(new RootObject
{
msg = "Model is not valid",
code = "error_03"
});
HttpContext.Response.StatusCode = 403;
HttpContext.Response.TrySkipIisCustomErrors = true;// Avoid issues in the HTTP methods
JsonRes.Message = rootObj;
return Json(JsonRes, JsonRequestBehavior.AllowGet);
}
}
catch (Exception ex)
{
string err = ex.ToString();
List<RootObject> rootObj = new List<RootObject>();
JsonRes.Issue = err;
rootObj.Add(new RootObject
{
msg = "Conflict with method, see issue description.",
code = "error_08"
});
HttpContext.Response.StatusCode = 400;// Bad request
HttpContext.Response.TrySkipIisCustomErrors = true;
JsonRes.Message = rootObj;
return Json(JsonRes, JsonRequestBehavior.AllowGet);
}
}
What's wrong with my code?
Thanks in advance.
As I can see you are not adding an item into the DbSet and calling SaveChanges after:
When adding an item you should put it into DbSet
context.CND_PersonalData.Add(item);
context.SaveChanges();
when you want to update just call SaveChanges after you update loaded object
var PersonalData= context.CND_PersonalData.Where(d => d.Id == ItemId && d.UserId == UserId).SingleOrDefault();
PersonalData.Name = item.Name;
PersonalData.Title = item.Title;
context.SaveChanges();
You can't just assign passed object to an entity you got from the DB, you need to change properties. If you do it as you did you didn't change values in the loaded object. So when you call SaveChanges nothing is changed. You need to change properties one by one.
If you don't want to do that then you can attach your item into the db by using Attach method on context.
context.Attach(item);
context.SaveChanges();
but you should be careful because if you load and track item with the same id as you are doing before checking if it is null:
CND_PersonalData PersonalData = context.CND_PersonalData.Where(d => d.Id == ItemId && d.UserId == UserId).SingleOrDefault();
if (PersonalData == null)
{
then you will get an error during the save because the context is already tracking item with the same ID, so you can remove that check and just check if it exists:
if (context.CND_PersonalData.Any(d => d.Id == ItemId && d.UserId == UserId))
{
and then execute your code

System.Data.Entity.Validation.DbEntityValidationException

I have a project that uses Entity Framework. While calling SaveChanges on my DbEntityValidationException, I get the following exception:
System.Data.Entity.Validation.DbEntityValidationException: 'Validation
failed for one or more entities. See 'EntityValidationErrors' property
for more details.'
This is all fine and dandy, but I don't want to attach a debugger every time this exception occurs. More over, in production environments I cannot easily attach a debugger so I have to go to great lengths to reproduce these errors.
How can I see the details hidden within the DbEntityValidationException?
private void btnCreateLetter_Click(object sender, EventArgs e)
{
using (TransactionScope TS = new TransactionScope())
{
try
{
Letter TblLetter = new Letter();
TblLetter.Subject = txtSubject.Text.Trim();
TblLetter.Abstract = txtAbstract.Text.Trim();
TblLetter.Body = ckeCKEditor.TextEditor.Text.Trim();
{
var LastLetterID = (from Letter in Database.Letters orderby Letter.LetterID descending select Letter).First();
TblLetter.LetterNO = PublicVariable.TodayDate.Substring(0, 4).Substring(2, 2) + PublicVariable.gDetermineJobLevel + "/" + (LastLetterID.LetterID + 1);
}
TblLetter.CreateDate = lblCreateDate.Text;
TblLetter.UserID = PublicVariable.gUserID;
if (rdbClassification.Checked == true)
{
TblLetter.SecurityType = 1;
}
else if (rdbConfidential.Checked == true)
{
TblLetter.SecurityType = 2;
}
else if (rdbSeries.Checked == true)
{
TblLetter.SecurityType = 3;
}
if (rdbActionType.Checked == true)
{
TblLetter.UrgencyType = 1;
}
else if (rdbInstantaneous.Checked == true)
{
TblLetter.UrgencyType = 2;
}
else if (rdbAnnie.Checked == true)
{
TblLetter.UrgencyType = 3;
}
TblLetter.ArchivesType = 1;
if (rdbFollowHas.Checked == true)
{
TblLetter.FollowType = 1;
}
else if (rdbFollowHasnoot.Checked == true)
{
TblLetter.FollowType = 2;
}
if (rdbAttachmentHas.Checked == true)
{
TblLetter.AttachmentType = 1;
}
else if (rdbAttachmentHasnot.Checked == true)
{
TblLetter.AttachmentType = 2;
}
TblLetter.ReadType = 1;
TblLetter.LetterType = 1;
TblLetter.DraftType = 1;
if (rdbResponseDeadlineHas.Checked == true)
{
TblLetter.AnswerType = 1;
TblLetter.AnswerReadLine = String.Format("{0:yyyy/MM/dd}", Convert.ToDateTime(pdpSetResponseDeadline.Value.Year.ToString() +
"/" + pdpSetResponseDeadline.Value.Month.ToString() + "/" + pdpSetResponseDeadline.Value.Day.ToString()));
}
else if (rdbResponseDeadlineHasnot.Checked == true)
{
TblLetter.AnswerType = 2;
}
Database.Letters.Add(TblLetter);
Database.SaveChanges();
if (rdbAttachmentHas.Checked == true)
{
if (lblPath.Text != "")
{
FileStream ObjectFileStream = new FileStream(lblPath.Text, FileMode.Open, FileAccess.Read);
int Lenght = Convert.ToInt32(ObjectFileStream.Length);
byte[] ObjectData;
ObjectData = new byte[Lenght];
string[] strPath = lblPath.Text.Split(Convert.ToChar(#"\"));
ObjectFileStream.Read(ObjectData, 0, Lenght);
ObjectFileStream.Close();
AttachFile TableAttachFile = new AttachFile();
TableAttachFile.FileSize = Lenght / 1024;
TableAttachFile.FileName = strPath[strPath.Length - 1];
TableAttachFile.FileData = ObjectData;
TableAttachFile.LetterID = TblLetter.LetterID;
Database.AttachFiles.Add(TableAttachFile);
Database.SaveChanges();
}
}
TS.Complete();
MessageBox.Show("saved", "ok", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (InvalidCastException ex)
{
MessageBox.Show(ex.ToString());
MessageBoxIcon.Error);
return;
}
}
}
You have to get the validation errors from the db.SaveChanges() method of the DatabaseContext object -- you can't get them where you are.
You can either modify the SaveChanges() method of your database context and wrap it in a try-catch block, or (since the class is partial) you can extend the partial class within your application and just override the SaveChanges() method.
There is a nice blog post about this called Easy way to improve DbEntityValidationException of Entity Framework here.
The essence of it is something like this:
public partial class NorthwindEntities
{
public override int SaveChanges()
{
try
{
return base.SaveChanges();
}
catch (DbEntityValidationException ex)
{
// Retrieve the error messages as a list of strings.
var errorMessages = ex.EntityValidationErrors
.SelectMany(x => x.ValidationErrors)
.Select(x => x.ErrorMessage);
// Join the list to a single string.
var fullErrorMessage = string.Join("; ", errorMessages);
// Combine the original exception message with the new one.
var exceptionMessage = string.Concat(ex.Message, " The validation errors are: ", fullErrorMessage);
// Throw a new DbEntityValidationException with the improved exception message.
throw new DbEntityValidationException(exceptionMessage, ex.EntityValidationErrors);
}
}
}
The blogger explains:
That’s it! The rest of your code will automatically use the overridden
SaveChanges so you don’t have to change anything else. From now on,
your exceptions will look like this:
System.Data.Entity.Validation.DbEntityValidationException: Validation
failed for one or more entities. See 'EntityValidationErrors' property
for more details. The validation errors are: The field PhoneNumber
must be a string or array type with a maximum length of '12'; The
LastName field is required.
The DbEntityValidationException also contains the entities that caused
the validation errors. So if you require even more information, you
can change the above code to output information about these entities.
As mention, you need to check on your EntityValidationError when it throws the exception.
You should fix that validation error, instead of asking bypass this exception.
Normally these errors are table allow length, data type, column does not allow null and etc. There will be exact fiend name mention in your exception too.

Exception thrown: 'System.Data.Entity.Infrastructure.DbUpdateException' when adding a registry

Im developing a web application in c# and it uses entity framework to make a connection to a sql server database. Everything works fine but there is a weird problem when im trying to add an entity, the program throws an exception when the changes in the DB are been committed, so none of them can be saved.
This is the controller code
[HttpPost]
public ActionResult AddEditEntidadFinanciera(AddEditEntidadFinancieraViewModel model)
{
try
{
using (var TransactionScope = new TransactionScope())
{
if (!ModelState.IsValid)
{
TryUpdateModel(model);
PostMessage(MessageType.Error, i18n.ValidationStrings.DatosIncorrectos);
return View(model);
}
sgTabEntidadFinanciera EntidadFinanciera;
sgTabReglaLimite regla;
if (model.EntidadFinancieraId.HasValue)
{
EntidadFinanciera = context.sgTabEntidadFinanciera.Find(model.EntidadFinancieraId.Value);
regla = context.sgTabReglaLimite.FirstOrDefault(x => x.fk_sgTabReglaLimite_sgTabEntidadFinanciera == EntidadFinanciera.PK_EntidadFinanciera);
if (regla == null)
{
regla = new sgTabReglaLimite();
regla.sgTabEntidadFinanciera = EntidadFinanciera;
context.sgTabReglaLimite.Add(regla);
}
}
else
{
EntidadFinanciera = new sgTabEntidadFinanciera();
regla = new sgTabReglaLimite();
regla.sgTabEntidadFinanciera = EntidadFinanciera;
EntidadFinanciera.fk_sgTabEntidadFinanciera_sgTabEstado = ConstantHelpers.ESTADO_SISTEMA_ENTIDAD_ACTIVO;
context.sgTabEntidadFinanciera.Add(EntidadFinanciera);
context.sgTabReglaLimite.Add(regla);
}
EntidadFinanciera.vRazonSocial = model.RazonSocial;
EntidadFinanciera.vDireccion = model.Direccion;
EntidadFinanciera.vRuc = model.Ruc;
EntidadFinanciera.vAcronimo = model.Acronimo;
EntidadFinanciera.fk_sgTabEntidadFinanciera_sgTabServidor = 1;
EntidadFinanciera.vFtp = model.Ftp;
EntidadFinanciera.vPasswordFtp = model.PasswordFtp;
EntidadFinanciera.vRazonSocial = model.RazonSocial;
EntidadFinanciera.vUsuarioFtp = model.UsuarioFtp;
EntidadFinanciera.vVcBin = model.VcBin;
EntidadFinanciera.vVcIPBancaDesarrollo = model.VcIPBancaDesarrollo;
EntidadFinanciera.vVcMascaraCuentaExterna = model.VcMascaraCuentaExterna;
EntidadFinanciera.vVcMascaraCuentaInterna = model.VcMascaraCuentaInterna;
EntidadFinanciera.iLimite = model.Limite;
if (model.Imagen != null && !String.IsNullOrEmpty(model.Acronimo))
{
var fileName = Guid.NewGuid().ToString().Substring(0, 4) + Path.GetFileName(model.Imagen.FileName);
var path = Path.Combine(Server.MapPath(ConstantHelpers.GetRutaImagenLogoEntidadFinanciera()), fileName);
if (!String.IsNullOrEmpty(EntidadFinanciera.vRuta))
{
System.IO.File.Delete(Server.MapPath(EntidadFinanciera.vRuta));
model.Imagen.SaveAs(path);
EntidadFinanciera.vRuta = ConstantHelpers.GetRutaImagenLogoEntidadFinanciera() + fileName;
}
}
//Here is when the exception is thrown
context.SaveChanges();
TransactionScope.Complete();
PostMessage(MessageType.Success);
return RedirectToAction("LstEntidadFinanciera");
}
}
catch (Exception ex)
{
ExceptionGlobokas exceptionGlobokas = new ExceptionGlobokas(ex.Message, log4net.Core.Level.Alert, ex);
InvalidarContext();
PostMessage(MessageType.Error);
model.Fill(CargarDatosContext(), model.EntidadFinancieraId);
TryUpdateModel(model);
return View(model);
}
}
This is the output after the error message is shown
Output
I already checked that my PK has identity enabled in my database, also i verify if there is a problem with entity framework versions in App.config and Web.config, so im not sure what is causing the problem.
EDIT
Here is the InnerException message
InnerExceptionImage
And this is the Stacktrace
at System.Data.Entity.Internal.InternalContext.SaveChanges()
at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
at System.Data.Entity.DbContext.SaveChanges()
at Globokas.SG.Controllers.AdminController.AddEditEntidadFinanciera(AddEditEntidad>FinancieraViewModel model) in D:\TFS_HL\Globokas.SG\Globokas.SG\Globokas.SG\Controllers\AdminController.cs:li>ne 2436

How to save changes in a DB for C#

I am trying to save the changes here and I am getting an exception error on db.SaveChanges(); I am trying to enter some content to the database and its saying that it needs to be validated.
Here is the error:
Validation failed for one or more entities. See
'EntityValidationErrors' property for more details.
Description: An unhandled exception occurred during the execution of
the current web request. Please review the stack trace for more
information about the error and where it originated in the code.
Exception Details:
System.Data.Entity.Validation.DbEntityValidationException: Validation
failed for one or more entities. See 'EntityValidationErrors' property
for more details.
using (GameConnection db = new GameConnection())
{
Game newGame = new Game();
int GameID = 0;
if (Request.QueryString.Count > 0)
{
GameID = Convert.ToInt32(Request.QueryString["gameID"]);
newGame = (from game in db.Games
where game.gameID == GameID
select game).FirstOrDefault();
}
newGame.teamA = teamATextBox.Text;
newGame.teamB = teamBTextBox.Text;
if (GameID == 0)
{
db.Games.Add(newGame);
}
db.SaveChanges();
Response.Redirect("~/Default.aspx");
}
}
The error is stating that at least one of the validation rules failed before submitting the request to the database.
What you need to do is check your class definition for Game (or database table) and check for NotNull or other restrictions and check if your input matches all these constraints by debugging the Game object before db.SaveChanges();
Even better, add a catch to print to the Console the Properties that failed:
using (GameConnection db = new GameConnection())
{
Game newGame = new Game();
int GameID = 0;
if (Request.QueryString.Count > 0)
{
GameID = Convert.ToInt32(Request.QueryString["gameID"]);
newGame = (from game in db.Games
where game.gameID == GameID
select game).FirstOrDefault();
}
newGame.teamA = teamATextBox.Text;
newGame.teamB = teamBTextBox.Text;
if (GameID == 0)
{
db.Games.Add(newGame);
}
try
{
db.SaveChanges();
}
catch (DbEntityValidationException ex)
{
foreach (var ve in eve.ValidationErrors)
{
Console.WriteLine(ve.PropertyName + " " + ve.ErrorMessage);
}
}
Response.Redirect("~/Default.aspx");
}

Create/Update method not allowed in "Activity Pointer" CRM 2011

Am having a plugin that moves the activities of lead to opportunity on qualify. I have registered the plugin on "Create" of opportunity and the following is the code
public void Execute(IServiceProvider serviceProvider)
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
Entity entity;
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
entity = (Entity)context.InputParameters["Target"];
if (entity.Attributes.Contains("originatingleadid") == false) return;
}
else
{
return;
}
try
{
//.....
EntityReference Lead = (EntityReference)entity.Attributes["originatingleadid"];
Guid LeadGuid = Lead.Id;
MoveActivitiesFromLeadToOpportunity(service, LeadGuid, Opportunityid);
}
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException(
"An error occurred in the plug-in.", ex);
}
}
private void MoveActivitiesFromLeadToOpportunity(IOrganizationService service, Guid LeadID, Guid OpportunityID)
{
ConditionExpression condition = new ConditionExpression();
condition.AttributeName = "regardingobjectid";
condition.Operator = ConditionOperator.Equal;
condition.Values.Add(LeadID.ToString());
var query = new QueryExpression("activitypointer");
query.Criteria.AddCondition(condition);
//query.Conditions.Add("reagrdingobjectid", ConditionOperator.Equal, theIdOfTheRelatedRecord);
query.ColumnSet = new ColumnSet(true);
var activities = service.RetrieveMultiple(query).Entities;
foreach (var activity in activities)
{
var castedActivity = (ActivityPointer)activity;
if (castedActivity.ActivityTypeCode == "email")
{
castedActivity.Id = Guid.NewGuid();
castedActivity["regardingobjectid"] = new EntityReference("opportunity", OpportunityID);
//service.Create(castedActivity);--->Exception thrown
//service.Update(castedActivity);---->Tried this one too.Exception is thrown stating method not supported on "ActivityPointer"
}
}
Can somebody shed light on this? Am i missing something here? Thank you
You need to query for the exact entity type, because you can't update an activitypointer
private void MoveEmailsFromLeadToOpportunity(IOrganizationService service, Guid LeadID, Guid OpportunityID)
{
ConditionExpression condition = new ConditionExpression();
condition.AttributeName = "regardingobjectid";
condition.Operator = ConditionOperator.Equal;
condition.Values.Add(LeadID.ToString());
var query = new QueryExpression("email");
query.Criteria.AddCondition(condition);
query.ColumnSet = new ColumnSet(true);
var emails = service.RetrieveMultiple(query).Entities;
foreach (var email in emails)
{
email["regardingobjectid"] = new EntityReference("opportunity", OpportunityID);
service.Update(email);
}
}
you can also write a method that will retrieve first all the activities (as you already did) check the ActivityTypeCode after retrieve and update each single record depending on activity type (email, fax, ...)
Try commenting out this line:
castedActivity.Id = Guid.NewGuid();
And then just do your Update:
service.Update(castedActivity)
You are just updating the RegardingObjectId, not creating a new activity, so you shouldn't change the Id and you shouldn't use Create.

Categories