saveChangesAsync update object I didn't save it - asp.net-core-mvc

I'm using entity framework core to get an object from the database this object I will use it to create another object, so my steps was
1- get object form database
2- change a property in this object
3- use this object to add another object of another type to database
4- call
await _context.AppLogs.AddAsync(log);
await _context.SaveChangesAsync();
after that EF add my object "log" and automatically update my first object property in the database
I want to ask if that valid, and why as I didn't call update function I just change a property!!

EF will automatically detect changes made to an existing entity that is tracked by the context. The entity is tracked when you load/query from the database . So that simply modify the values assigned to properties and then call SaveChanges will automatically update the database :
var blog = context.Blogs.First();
blog.Url = "http://sample.com/blog";
context.SaveChanges();
If you don't want to update database for the entity , you can set entity state to Unchanged:
var blog = context.Blogs.First();
blog.Url = "http://sample.com/blog";
context.Entry(blog).State = EntityState.Unchanged;
context.SaveChanges();
Unchanged entities are not touched by SaveChanges. Updates are not sent to the database for entities in the Unchanged state.

Related

Update a single property of an entity with EF Core

var user = _context.Users.Single(u => u.Id == userId);
user.AssignedInfo = _mapper.Map<AssignedInfo>(assignedInfoDTO);
_context.SaveChanges();
In this case with EF, after the query with the method Single, all other properties but AssignedInfo on the user entity will be overwritten? or are skipped and only the AssignedInfo property is updated?
I ask this because there's a big chance some other users may update those other columns of the table from other endpoints in the api, so I don't want to overwrite other properties than AssignedInfo on this particular endpoint.
Does it work that way or it does update the entire row with all the fields obtained in the query? I just need to update that particular property, and that's the only point where that property is being updated.
When you use Single method, EF Core starts to track the selected row, which is user with userId that is intended. Then after changes in user properties, when you use SaveChanges(), EF Core intelligently generates a query which only updates the fields that has been changed, which in your case is AssignedInfo. So the generated query will be something like :
UPDATE [Users] SET [AssignedInfo ] = #p0
WHERE [Id] = #p1;
This is a parameterized query (to prevent from SQL injection) so :
#p0 = _mapper.Map<AssignedInfo>(assignedInfoDTO)
and
#p1 = userId
By the way, you can see the EF Core generated queries just by adding
"Microsoft.EntityFrameworkCore.Database.Command": "Information"
to LogLevel property of Logging property of appsettings.Development.json, so in development mode the queries are shown in the command window or vs output window.

Does Entity Framework automatically load all of my data (not a reference and lazy load is off)?

I have a database first Entity Framework project. For every entity that I add, a collection is added to the DbContext for the entity. I explicity set LazyLoadingEnabled = false in the DbContext constructor. If I break into the following code and check the count of CustomerDepartments, I get the total count of the table. If I'm just adding a new record, I expect the count to be 0 before I add, and 1 after. I'm using this in a stateless environment, so loading the whole table just to add a record seems absurd. What am I doing wrong?
using (Model.SupportEntities support = new Model.SupportEntities(_state.Credentials, _handler.ReadWriteConnectionString))
{
Model.CustomerDepartment department = Json.JsonConvert.DeserializeObject<Model.CustomerDepartment>(_insertObject);
support.CustomerDepartments.Add(department);
support.SaveChanges();
_state.ReturnNewIdAsJson(department.CustomerDepartmentID);
}
It seems you have misinterpreted how DbContext and DbSet works.
It maybe best if you get hold of a tool for logging EntityFramework SQL calls try Clutch.Diagnostics.EntityFramework.
When you call IEnumerable<T>.Count() on DbSet<T>, Entity Framework runs the following query
SELECT COUNT(*) FROM TableName;
But it does not load the whole table.
The ACTUAL call you want for the behavior you wanted was either
support.CustomerDepartments.Local.Count;
OR
support.ChangeTracker.Entries<T>().Count()
These will NOT hit the database.
You have to remember that DbSet is an abstraction for the Database table, so calling Count() on it should tell you how many rows there are in the table.
BTW. FYI. The convention is call name your DbContext to be SupportContext. Model named classes or namespace suggests they are your POCOs.

Get original object property stored in DB with Hibernate in same transaction

I opened hibernate transaction and read the object. I changed some properties of object without store. I want to get the original properties stored in DB but with
Criteria cr = new Criteria(...);
cr.add(Restrictions.eq("id", id));
cr.setProjection(Projections.property("someProperty"));
cr.uniqueResult();
or reload whole object with getSession().get(id). But as a result I got changed properties and if I reload whole object I got the same instance of changed object. How to get original object properties stored in DB with same transaction, changed object must remain with changed properties.
And how to do it with Spring transaction annotations?
You can use session.refresh() method. See documentation: http://docs.jboss.org/hibernate/orm/4.1/manual/en-US/html_single/#objectstate-loading
But this will overwrite any changes. You can clone the object before refresh, i think.

Does instantiating a DbContext From EF read the whole database?

When instantiating EntityFramework's DbContext in MVC3, does the whole database get read? When debugging, it is possible to access all of the data in the entire database by looking at the instantiated DbContext so wouldn't this imply that all the data is grabbed when the first connection is made?
No definitly not. The data is loaded, when you access the DbSet/ObjectSet properties of your DbContext.
Only the data you query for is loaded from the db and mapped to objects. For example, when you query like
DbContext.Table.Where(row => row.Prop1 == "Value")
Its translated to SQL, evaluated at the database and only the rows that match your query are returned to your app.
No, the entire database is not read on instantiation. The entity collections (DbSet<>) in your DbContext are lazy evaluated. So when you're debugging and navigate into one, it's being queried then, not when the DbContext instance is instantiated.
No, Entity Framework tries to only query the database when you need information, or you need to modify information.
The following example is my personal interpretation of what I think EF is doing behind the scenes. It's probably somewhat inaccurate, but serves a point for illustration purposes.
using(var db = new MyDbContext()) // 1
{
var entities = db.MyEntities; // 2
foreach(var entity in entities) // 3
{
// 4
} // 5
} // 6
Establish connection with database
Get some object representing a query that says "Get me all dem entities."
Enumerate the object. Aka, have the context's query provider translate "get me all dem entites" to (assuming sql) "select * from MyEntity with (nolock);", and run the query returning an ADO.NET SqlDataReader, which will read the first row, map the object into an (optionally) lazy object with some metadata, so EF knows what row it's mapped to, etc, and yeild that as the "entity" variable.
Do something with the entity you magically received from the database without actually doing any real work (thank Entity Framework!)
Ask EF to move the SqlDataReader to the next row and yield another entity (aka, go back to step 3, but only if another row exists)
Close the connection with the database.

MSCRM: How to create entities and set relations using the xRM linq provider

Do I need to save newly created CRM-entity instances before I can set relations to other crm entity instances?
I'm facing the problem that after calling CrmDataContext.SaveChanges() the newly created entities are written to the database, but the relations between those newly created instances are missing in the database.
What do I miss? Do I have to call CrmDataContext.SaveChanges() each time I create a new crm entity instance that I want to have relations to other CRM-entity instances?
You should be able to set relationships to other entities in a 1:N relationship before saving this entity(i.e. a lookup).
If you are wanting your entity to be referenced by another entity it will need to be Saved first OR you need to set a Guid for the entity first. Otherwise your link won't stick.
When you new up an entity its id is not set until it is saved to the database, unless you set it manually. If you set it manually it will respect the new Guid you have given it and the relationship will survive the saving process.
If you try to save an entity individually, you need to make sure that you have saved all the entities that it refers to before you save that entity, or it won't have a link.

Resources