I Trying to insert the data into Database By using entity framework but it throwing error following
An error occurred while updating the entries. See the inner exception for details.
Code is Here
public int InsertUserData(UserDetail userDetail, BusinessObjects objects)
{
try
{
UserCredential objCredentials = newPersonEntity.UserCredentials
.First(cd => cd.UserName == objects.UserName);
objCredentials.Status = objects.Status;
newPersonEntity.UserDetails.Add(userDetail);
int result=newPersonEntity.SaveChanges();
return result;
}
catch (Exception ex)
{
CatchError(ex);
return 3;
}
}
Can Any One Tell what mistake i did ?
As i undestand your code snipped correctly, you don't need to perform operations with objCredentials. Or if you want to change its status, you must call
newPersonEntity.UpdateObject(objCredentials);
And the only reason, why you cannot save changes is incorrect userDetail object fields values. Check that all required fields filled correclty and don't conflict with existing key values, stored in dataBase
Related
I'm on a team using an EF, Code-first approach with ODP.Net (Oracle). We need to attempt to write updates to multiple rows in a table, and store any exceptions in a collection to be bubbled up to a handler (so writing doesn't halt because one record can't be written). However, this code throws an exception saying
System.InvalidOperationException: The operation cannot be completed because the DbContext has been disposed.
I'm not sure why. The same behavior occurs if the method is changed to be a synchronous method and uses .Find().
InvModel _model;
public InvoiceRepository(InvModel model)
{
_model = model;
}
public void SetStatusesToSent(IEnumerable<Invoice> Invoices)
{
var exceptions = new List<Exception>();
foreach (var id in invoices)
{
try
{
var iDL = await _model.INVOICES.FindAsync(id);/*THROWS A DBCONTEXT EXCEPTION HERE*/
iDL.STATUS = Statuses.Sent; // get value from Statuses and assign
_model.SaveChanges(); //save changes to the model
}
catch (Exception ex)
{
exceptions.Add(ex);
continue; //not necessary but makes the intent more legible
}
}
}
Additional detail update: _model is injected by DI.
Remember that LINQ executes lazily - that is when you actually use the information.
The problem might be, that Your DbContext has gone out of scope...
Use .ToList() or .ToArray() to force execution at that time.
I am porting app from EF 6 to EF Core 2.2. I have an object with some related objects inside, each one with database generated ID and GUID (db - postgresql).
I'm trying to create a generic method to add a whole object graph with all related objects the same way as in EF 6 - like this:
var res = context.Set<T>().Add(entity);
Before the insert, EF make temporary IDs, which will be replaced with real database IDs.
So, because inside different object I might have exactly the same objects (for better understanding, my subject area is medicine, I have several different analyzes that are performed from the same sample), in EF Core I can't add whole object graph like this - getting errors, for example:
Key (\"ID\")=(5) already exists
But in the EF 6 version, everything used to work - all objects are inserted including inner objects with correct IDs and GUIDs, without duplicates.
In both versions, temporary IDs in the same objects are also equal, but only in EF Core version, I'm getting this error.
I have tried add attributes
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
tried changing the DbContext
modelBuilder.Entity<Sample>().Property(e => e.ID).ValueGeneratedOnAdd();
but neither works for me - I think the problem is not here.
Also I found this article in Microsoft docs, which says
If the graph does contain duplicates, then it will be necessary to process the graph before sending it to EF to consolidate multiple instances into one.
but I'm not sure - is this about my case?
Am I doing this wrong or is it impossible in EF Core 2.2?
Magic sauce: Create an interface and implement it on object you don't want to save on the object graph, then simply do not set that object as modified. The paradigm that I was failing to understand was that I never really wanted to save a 'defining' object during a save when that object was being used to define the object being saved.
I save the defining objects with a separate process. Works perfectly.
public virtual T InsertOrUpdate(T oneObject)
{
T output = null;
if (oneObject.Id == Guid.Empty)
{
output = this.Insert(oneObject);
}
else
{
try
{
_dbContext.ChangeTracker.TrackGraph(oneObject, e =>
{
if (e.Entry.IsKeySet)
{
// See if the entry has interface with 'StaticObject'
List<Type> x = e.Entry.Entity.GetType().GetInterfaces().ToList();
if (x.Contains(typeof(IStaticObject)))
{
_logger.LogWarning($"Not tracking entry {e.Entry}");
}
else
{
e.Entry.State = EntityState.Modified;
}
}
else
{
e.Entry.State = EntityState.Added;
}
});
_dbContext.Entry(oneObject).State = EntityState.Modified;
_dbContext.SaveChanges();
output = oneObject;
}
catch (Exception ex)
{
_logger.LogError(ex, $"Problem updating object {oneObject.Id}");
}
}
return output;
}
public virtual T Insert(T oneObject)
{
try
{
_dbContext.Attach(oneObject);
_dbContext.Entry(oneObject);
_dbContext.SaveChanges();
}
catch (Exception error)
{
_logger.LogError(error.Message, error);
}
return oneObject;
}
I have a code like this:
try
{
Member member = database.Members.Where(m=>m.ID=1).FirstOrDefault();
member.Name = "NewMemberName";
database.Entry(member).State = EntityState.Modified;
database.SaveChanges();
}
catch (Exception ex)
{
database.Logs.Add(new Log() { Value=ex.ToString() });
database.SaveChanges();
}
And Entity:
[StringLength(5)]
public string Name { get; set; }
If the Name String more than 5 it would be error and catch the exception ,but when I add a log then save ,the exception from SaveChange(); still remains,how should I do?(Can't change the schema)
the exception from SaveChange(); still remains
Well, if this throws an exception:
database.SaveChanges();
Then there's a pretty good chance that this will also throw an exception:
database.SaveChanges();
Basically, in your catch block you shouldn't be immediately re-trying the operation that just failed a millisecond ago. Instead, log the failure and handle the exception:
catch (Exception ex)
{
// DO NOT call SaveChanges() here.
}
Of course, if writing to the database is failing, then logging to the database is also likely to fail. Suppose for example that the connection string is wrong or the database is down or timing out. You can't log that.
I recommend using a logging framework (log4net, NLog, etc.) as a separate dependency from your Entity Framework data access layer. It's a small learning curve, but you end up with a pretty robust logging system that can much more effectively handle problems. And can be easily configured to log to multiple places, so if writing to one error log (the database) fails then you still have another one (a file, for example).
At the very least, if persisting your data context fails, you'll need to log to a new data context. Otherwise the part that failed is still there.
Something structurally more like this:
try
{
using (var database = new DbContext())
{
Member member = database.Members.Where(m=>m.ID=1).FirstOrDefault();
member.Name = "NewMemberName";
database.Entry(member).State = EntityState.Modified;
database.SaveChanges();
}
}
catch (Exception ex)
{
using (var database = new DbContext())
{
database.Logs.Add(new Log() { Value=ex.ToString() });
database.SaveChanges();
}
}
I have an application with multiple edmx. some times I need to insert or update data in different table of different edmx.
Now I'am concern if insertion of data failed after inserting data in one table.
Which can handle by sql transaction but i want do it using Entity Frame work in multiple edmx at once.
Please help me through, i'm giving a sample code alike what i'm working on
public bool SaveInformation(Other_Admission otherAdmission, Account_Bill aBill)
{
_aRepository.OtherAdmission.Insert(otherAdmission); //Assume this is Admission edmx
aBill.StudentRoll=otherAdmission.StudentRoll;
_aBillRepository.Bill.Insert(aBill); //Assume this is Account edmx
_aRepository.SaveChanges();
_aBillRepository.SaveChanges();
return true;
}
public bool SaveInformation(Other_Admission otherAdmission, Account_Bill aBill)
{
using (var transaction = _aRepository.BeginTransaction())
{
try
{
_aRepository.OtherAdmission.Insert(otherAdmission); //Assume this is Admission edmx
aBill.StudentRoll=otherAdmission.StudentRoll;
_aBillRepository.Bill.Insert(aBill); //Assume this is Account edmx
_aRepository.SaveChanges();
_aBillRepository.SaveChanges();
return true;
}
}
catch (Exception ex)
{
transaction.Rollback();
}
}
In my application I have the following code...
public Boolean SaveUserInformation(UserInfoDTO UserInformation)
{
return dataManager.SaveUserInfo(new UserInfo()
{
UserInfoID = UserInformation.UserInfoID.HasValue ? UserInformation.UserInfoID.Value : 0,
UserID = UserInformation.UserID,
ProxyUsername = UserInformation.ProxyUsername,
Email = UserInformation.Email,
Status = UserInformation.Status
});
}
This code calls a method on a dataManager object that utilizes Entity Framework...
public Boolean SaveUserInfo(UserInfo userInfo)
{
try
{
//Validate data prior to database update
if (userInfo.UserID == null) { throw new Exception("UserInfoDomainModel object passed to PriorityOne.Data.DataManager.SaveUserInfo with UserID property set to NULL."); }
if (userInfo.ProxyUsername == null) { throw new Exception("UserInfoDomainModel object passed to PriorityOne.Data.DataManager.SaveUserInfo with ProxyUsername property set to NULL."); }
if (userInfo.Email == null) { throw new Exception("UserInfoDomainModel object passed to PriorityOne.Data.DataManager.SaveUserInfo with Email property set to NULL."); }
if (userInfo.UserInfoID == 0)
{
//Perform Insert
using (PriorityOneEntities entities = new PriorityOneEntities())
{
entities.UserInfoes.AddObject(userInfo);
entities.SaveChanges();
}
}
else
{
//Perform Update
using (PriorityOneEntities entities = new PriorityOneEntities())
{
entities.Attach(userInfo);
entities.SaveChanges();
}
}
return true;
}
catch (Exception ex)
{
//TODO: Log Error
return false;
}
}
The insert on this code works just fine. But when I try to perform an update I'm getting an error saying: "An object with a null EntityKey value cannot be attached to an object context."
It occurs on this line of code: entities.Attach(userInfo);
What I'm trying to accomplish is to avoid making a round trip to the database just to select the record that I will later make changes to and update, thus making two round trips to the database.
Any ideas what is going wrong, or how I could better accomplish this?
Thanks.
Seems like you're using EF 4.1+
You have to tell EF that you want your entity to be updated (Modified state):
//Perform Update
using (PriorityOneEntities entities = new PriorityOneEntities())
{
entities.Entry(userInfo).State = EntityState.Modified;
entities.SaveChanges();
}
P.S. You don't have to explicitly call Attach. It's done under the hood.
Update:
based on your comments, you're using EF 4.0. Here's what you have to do to attach your object as modified in EF 4.0:
ctx.AddObject("userInfoes", userInfo);
ctx.ObjectStateManager.ChangeObjectState(userInfo, EntityState.Modified);
ctx.SaveChanges();
You cannot use Attach method. From http://msdn.microsoft.com/en-us/library/bb896271.aspx:
If more than one entity of a particular type has the same key value, the Entity Framework will throw an exception. To avoid getting the exception, use the AddObject method to attach the detached objects and then change the state appropriately.
From MSDN
The object that is passed to the Attach method must have a valid
EntityKey value. If the object does not have a valid EntityKey value,
use the AttachTo method to specify the name of the entity set.
Hope this will help you.