EF Core 6 changes boolean false value to default true from Fluent API on save changes - entity-framework-core

This is my code
var data = new Data();
data.ID = Guid.NewGuid();
data.Active = false;
_context.Data.Add(data);
_context.SaveChanges();
If I put breakpoint on _context.SaveChanges(), and put mouse over data.Active it's false, but next line after saving it becomes true.
I got this in OnModelCreating, but how it cannot be explicitly changed to non default one.
modelBuilder.Entity<Data>()
.Property(t => t.Active)
.HasDefaultValue(true);

Related

Entity Core and SaveChanges works only once

I have problem with Entity Core 3.1.2.
I have code like this:
SQL.Database.EnsureCreated();
var ThisCollector = SQL.CollectorServers
.Where(esa => esa.ServerName == ServerCollectorName)
.FirstOrDefault();
while (foo)
{
await SQL.Entry(ThisCollector)
.ReloadAsync();
DateTime dtTimeOut = DateTime.UtcNow.AddMinutes(-1);
//check status of current Worker
var CurrentLB = SQL.CollectorServers
.Where(esa => esa.isWorker == true
&& esa.LastSeenLB < dtTimeOut)
.FirstOrDefault();
if (CurrentLB!=null) //Current Worker is dead!
{
CurrentLB.isWorker = false;
ThisCollector.isWorker = true;
SQL.SaveChanges(); //This works allways
}
var Collectors = SQL.CollectorServers
.Where(Esa => Esa.isWorker == true);
if (Collectors.Count() == 0)
{
ThisCollector.isWorker = true;
SQL.SaveChanges();
}
if (Collectors.Count() >= 2)
{
foreach(CollectorServer cs in Collectors)
{
cs.isWorker = false;
//why this is requied?
SQL.Entry(cs).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
}
ThisCollector.isWorker = true;
//<--This works only once, without manually setting State to
// modified!!! Why? Values has been changed from external program.
//(Management studio in this case)
SQL.SaveChanges();
}
await Task.Delay(10000, stoppingToken);
}
Problem is that last SaveChanges works only first time it has been called without I set Entry state to Modified. After that it does not make SQL query (I can see that in SQL Profiler).
In this case this can be fixed by this way, but I'm trying to undestand why this happends. My software saves lot data to SQL, and I need to know can I trust to this code without opening all queries and adding this modified state.
I didin't have this kind of problems in full version (6) of Entity, this is something quite new for me.
The described behavior would make sense if the entities returned by CollectorServers are not tracked.
ThisCollector is attached on every loop by the call to SQL.Entry(ThisCollector) :
await SQL.Entry(ThisCollector) //Attaching
.ReloadAsync(); //Reloading
Any changes made to it would be tracked and saved by the first call to DbContext.SaveChanges().
On the other hand, the entities returned by the Collectors query :
var Collectors = SQL.CollectorServers
.Where(Esa => Esa.isWorker == true);
Would remain untracked, until they get reattached by the call to SQL.Entry(cs) :
foreach(CollectorServer cs in Collectors)
{
cs.isWorker = false;
SQL.Entry(cs).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
}
That's equivalent to calling DbContext.Update to attach and set the state to Modified. Update is easier to read though :
foreach(CollectorServer cs in Collectors)
{
cs.isWorker = false;
SQL.Update(cs);
}

Entity Framework 6: is it possible to update specific object property without getting the whole object?

I have an object with several really large string properties. In addition, it has a simple timestamp property.
What I trying to achieve is to update only timestamp property without getting the whole huge object to the server.
Eventually, I would like to use EF and to do in the most performant way something equivalent to this:
update [...]
set [...] = [...]
where [...]
Using the following, you can update a single column:
var yourEntity = new YourEntity() { Id = id, DateProp = dateTime };
using (var db = new MyEfContextName())
{
db.YourEntities.Attach(yourEntity);
db.Entry(yourEntity).Property(x => x.DateProp).IsModified = true;
db.SaveChanges();
}
OK, I managed to handle this. The solution is the same as proposed by Seany84, with the only addition of disabling validation, in order to overcome issue with required fields. Basically, I had to add the following line just before 'SaveChanges():
db.Configuration.ValidateOnSaveEnabled = false;
So, the complete solution is:
var yourEntity = new YourEntity() { Id = id, DateProp = dateTime };
using (var db = new MyEfContextName())
{
db.YourEntities.Attach(yourEntity);
db.Entry(yourEntity).Property(x => x.DateProp).IsModified = true;
db.Configuration.ValidateOnSaveEnabled = false;
db.SaveChanges();
}

Which is the good way to update object in EF6

I have searched and find 2 way to update object in EF
var attachedEntity = _context.EntityClasses.Local.First(t => t.Id == entity.Id);
//We have it in the context, need to update.
if (attachedEntity != null)
{
var attachedEntry = _context.Entry(attachedEntity);
attachedEntry.CurrentValues.SetValues(entity);
}
else
{
////If it's not found locally, we can attach it by setting state to modified.
////This would result in a SQL update statement for all fields
////when SaveChanges is called.
var entry = _context.Entry(entity);
entry.State = EntityState.Modified;
}
_context.SaveChanges();
And other way is seem more easy
var entity = _context.EntityClasses.FirstOrDefault(t => t.Id == entity.Id);
_context.Entry(entity ).EntityState.Modified
_context.SaveChanges();
What is best way to update object?
NOTE: the performence is importance with me
_context.EntityClasses.Local.First(t => t.Id == entity.Id)
=> means that you want to double check the entity on local (the latest loading from DB) and it is not send to DB to find the record so the performance is faster.
_context.EntityClasses.FirstOrDefault(t => t.Id == entity.Id): This command is look up the entity in DB. That means EF creates the query and look up in DB.
The below link is the difference of between Entity.Local.Find & Entity.Find http://msdn.microsoft.com/en-us/data/jj592872.aspx
Hope it helps!

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

Set property back to original value on saving in 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);
}
}
}