Set property back to original value on saving in Entity Framework - entity-framework

In the "SavingChanges" event of the Entity Framework context, is there a way to ignore any changes that were made to a specific field/property?
Specifically, I have a property on my entity "CreatedBy". I need to set this property in the application, but once it is set (when the entity state is "Added"), I want the property to be available, but do not want anybody to be able to change the value.
Does anyone know how to ignore changes to this field?
Thanks.

This code in the "SavingChanges" event handler seems to take care of it.
foreach (ObjectStateEntry entry in ((ObjectContext)sender).ObjectStateManager.GetObjectStateEntries(EntityState.Modified))
{
if (!entry.IsRelationship)
{
if (entry.GetModifiedProperties().Count(p => p == "CreatedBy") > 0)
{
Guid cb = entry.OriginalValues.GetGuid(entry.OriginalValues.GetOrdinal("CreatedBy"));
PropertyInfo createdBy = entry.Entity.GetType().GetProperty("CreatedBy");
createdBy.SetValue(entry.Entity, cb, null);
}
if (entry.GetModifiedProperties().Count(p => p == "CreatedDate") > 0)
{
DateTime cd = entry.OriginalValues.GetDateTime(entry.OriginalValues.GetOrdinal("CreatedDate"));
PropertyInfo createdDate = entry.Entity.GetType().GetProperty("CreatedDate");
createdDate.SetValue(entry.Entity, cd, null);
}
}
}

Related

Entity Framework: check if object exists and check if it has an associated object

In a many-to-many relationship between File and Category I want to check if a file exists and if so, if it has any categories (because there's a chance it may not have any) :
public bool existsInDBAndHasCategories(string path)
{
using (WinFileContextContainer c = new WinFileContextContainer())
{
return c.File.Any((o => o.path == path));
}
}
This checks if a file with this path has a record in the database. I got this from a thread on this site. Truth be told I am still not good with LINQ and lambdas, so I don't know how to extend it to give me BOOLEAN for any categories as well. Thanks in advance for the time.
You just have to add another condition to your method (Assuming you have defined Categories as a list of Category in File class) :
return c.File.Any((o => o.path == path && o.Categories.Any()));
If you are not familiar with Lamba, start learning simple LinQ, before you move on to lambda inside Linq queries.
You code shoud be like this:
public bool existsInDBAndHasCategories(string path)
{
using (WinFileContextContainer c = new WinFileContextContainer())
{
var query = from f in c.File
where f.Path == path &&
(f.Categories != null || f.Categories.Count != 0)
select f;
return (f.Count != 0)
}
}

Entity Framework dbset not finding added entity

I am having an issue understanding why when adding a new entity to a DbSet of ObjectContext, that entity is not found will looking it up again.
using (var db = new SmartrailDB())
{
var cart01 = db.Carts.SingleOrDefault(x => x.Number == 0);
if (cart01 == null)
{
cart01 = new Cart { Number = 0 };
db.Carts.Add(cart01);
}
var cart02 = db.Carts.SingleOrDefault(x => x.Number == 0); // Should find the cart I just added - right?
Assert.IsNotNull(cart02); // Fails because cart02 does not exist in the db.Carts collection
}
Is anyone able to tell me what I am doing wrong here?
Also late on a Friday here so brain half asleep now.
You have to update your context before you try to access the entity. Just do:
db.SaveChanges(); right after db.Cart.Add(cart01);

Does entity framework compare assigned values with original to determine IsModified flag?

If I load entity object and then assign one of properties to the same value as it had before, does framework detect changes or it would set IsModified flag to true anyway ?
This is how generated code for field Name looks like:
OnNameChanging(value);
ReportPropertyChanging("Name");
_Name = StructuralObject.SetValidValue(value);
ReportPropertyChanged("Name");
OnNameChanged();
I don't know which of those events set IsModified flag for that field and for the whole entity.
It looks like things are different now (EF6). I was researching this to see if I needed to use an if statement when setting property values to see if the "new value" is different. I tested with the following and the entity is not marked as modified:
var things = dbContext.Things.AsQueryable();
var thing = things.First();
string name = thing.Name;
thing.Name = name;
var entry = dbContext.Entry(thing);
var state = entry.State;
int count = dbContext.ChangeTracker.Entries().Count(e => e.State == EntityState.Modified);
var modified = entry.Property(x => x.Name).IsModified;
Your context only keeps track if your data got modified, not if it's different.
You can do a check like this:
private void CheckIfDifferent(DbEntityEntry entry)
{
if (entry.State != EntityState.Modified)
return;
if (entry.OriginalValues.PropertyNames.Any(propertyName => !entry.OriginalValues[propertyName].Equals(entry.CurrentValues[propertyName])))
return;
(this.dbContext as IObjectContextAdapter).ObjectContext.ObjectStateManager.GetObjectStateEntry(entry.Entity).ChangeState(EntityState.Unchanged);
}
source:https://stackoverflow.com/a/13515869/1339087

updating table in entity framework 4 /mvc 3!

could you help with this? I bet this isn't any tough one..but am new to EF and facing a weekend deadline. I want to update a table with values.. but the primary key is identity column. So my task is like this.. if it exists, update.. if it doesn't add to the
table.. this is my code..and am stuck in this else part..!
Table structure is like this
Primary Key table - System: SystemId, SystemName
Foreign Key table - SystemConfiguration: SystemConfigurationId, SystemId, SystemRAM, SystemHard-Disk
public void SaveSystemConfigurations(SystemConfiguration systemConfig)
{
var config = (from s in Context.SystemConfiguration
where s.SystemId == systemConfig.SystemId
select s).FirstOrDefault();
if (config == null)
{
Context.SystemConfigurations.AddObject(systemConfig);
Context.SaveChanges();
}
else
{
// EntityKey systemConfigKey= new EntityKey("systemConfig", "systemConfigId", config.SystemConfigurationId);
Context.SystemConfigurations.Attach(systemConfig);
Context.SaveChanges();
}
}
Try this:
public void SaveSystemConfigurations(SystemConfiguration systemConfig)
{
var config = (from s in Context.SystemConfiguration
where s.SystemId == systemConfig.SystemId
select s).FirstOrDefault();
if (config == null)
{
Context.SystemConfigurations.AddObject(systemConfig);
}
else
{
config.Attribute = value; // Do your update here
}
Context.SaveChanges();
}
Edit. It should be config not systemConfig.
The ApplyCurrentValues method will apply scalar attributes to an entity that matches the same key. My assumption is that you are modifying a real entity (an object that has a valid entity key).
This would work:
var eSet = config.EntityKey.EntitySetName;
Context.ApplyCurrentValues(eSet, systemConfig);
Context.SaveChanges();
public void SaveSystemConfigurations(SystemConfiguration systemConfig)
{
var context = new EntitiesModel();
//here is the name of the partial class created on the Context area of the edmx designer.cs
var config = (from s in context.SystemConfiguration
where s.SystemId == systemConfig.SystemId
select s).FirstOrDefault();
context.ApplyCurrentValues(config.EntityKey.EntitySetName, systemConfig);
// systemConfig comes from the view with values set by the user
// you dont have to manually need to map one value at the time
context.SaveChanges();
}

Is there an Update Object holder on Entity Framework?

I'm currently inserting/updating fields like this (if there's a better way, please say so - we're always learning)
public void UpdateChallengeAnswers(List<ChallengeAnswerInfo> model, Decimal field_id, Decimal loggedUserId)
{
JK_ChallengeAnswers o;
foreach (ChallengeAnswerInfo a in model)
{
o = this.FindChallengeAnswerById(a.ChallengeAnswerId);
if (o == null) o = new JK_ChallengeAnswers();
o.answer = FilterString(a.Answer);
o.correct = a.Correct;
o.link_text = "";
o.link_url = "";
o.position = FilterInt(a.Position);
o.updated_user = loggedUserId;
o.updated_date = DateTime.UtcNow;
if (o.challenge_id == 0)
{
// New record
o.challenge_id = field_id; // FK
o.created_user = loggedUserId;
o.created_date = DateTime.UtcNow;
db.JK_ChallengeAnswers.AddObject(o);
}
else
{
// Update record
this.Save();
}
}
this.Save(); // Commit changes
}
As you can see there is 2 times this.Save() (witch invokes db.SaveChanges();)
when Adding we place the new object into a Place Holder with the AddObject method, in other words, the new object is not committed right away and we can place as many objects we want.
But when it's an update, I need to Save first before moving on to the next object, is there a method that I can use in order to, let's say:
if (o.challenge_id == 0)
{
// New record
o.challenge_id = field_id;
o.created_user = loggedUserId;
o.created_date = DateTime.UtcNow;
db.JK_ChallengeAnswers.AddObject(o);
}
else
{
// Update record
db.JK_ChallengeAnswers.RetainObject(o);
}
}
this.Save(); // Only save once when all objects are ready to commit
}
So if there are 5 updates, I don't need to save into the database 5 times, but only once at the end.
Thank you.
Well if you have an object which is attached to the graph, if you modify values of this object, then the entity is marked as Modified.
If you simply do .AddObject, then the entity is marked as Added.
Nothing has happened yet - only staging of the graph.
Then, when you execute SaveChanges(), EF will translate the entries in the OSM to relevant store queries.
Your code looks a bit strange. Have you debugged through (and ran a SQL trace) to see what is actually getting executed? Because i can't see why you need that first .Save, because inline with my above points, since your modifying the entities in the first few lines of the method, an UPDATE statement will most likely always get executed, regardless of the ID.
I suggest you refactor your code to handle new/modified in seperate method. (ideally via a Repository)
Taken from Employee Info Starter Kit, you can consider the code snippet as below:
public void UpdateEmployee(Employee updatedEmployee)
{
//attaching and making ready for parsistance
if (updatedEmployee.EntityState == EntityState.Detached)
_DatabaseContext.Employees.Attach(updatedEmployee);
_DatabaseContext.ObjectStateManager.ChangeObjectState(updatedEmployee, System.Data.EntityState.Modified);
_DatabaseContext.SaveChanges();
}