Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

EntityFramework Core 1.1 detailed explanation of how to use Add, Attach, Update and Remove methods efficiently

2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Database >

Share

Shulou(Shulou.com)06/01 Report--

Detailed explanation of EntityFramework Core 1.1Method Theory

When we use EF Core to query the database, if we do not explicitly turn off change tracking, the entity is tracked, which we will talk about in the next section. As we discussed earlier in EF 6.x, it is not recommended to turn off change tracking manually, and in some special cases, turning off change tracking can cause many problems.

Entity state

There are still four states in EF Core 1.1, and some people say that there are five states: UnChanged, Added, Modified, Deleted, and Detached. If we divide it according to change tracking, there are actually only four, excluding Detached, and Detached will not be tracked by context. So how did the state change? There is an IStateManager interface inside, through which the entity state is managed. At this time, depending on how the SaveChanges is handled behind the call, I just looked at the source code a little, and didn't do much research on anything in depth.

Added: the entity has not been inserted into the database yet. When SaveChanges is called, its state will be modified and the entity will be inserted into the database.

UnChanged: the entity exists in the database but is not modified on the client side and will be ignored when SaveChanges is called.

Modified: the entity is stored in the database, and the entity is modified on the client side. When SaveChanges is called, its state is changed and the updated data is persisted to the database.

Deleted: the entity exists in the database and will be deleted when the SaveChanges method is called.

Entity method

There are still Add, Attach, Update methods in EF Core 1.1, and we can see through the context or DbSet that when entities are passed to these methods, they are closely related to entity tracking Datuk, for example, the publication of the blog's navigation attributes we discussed earlier, when we add the entity of the article's publication, and then after calling the Add method, the post's publication entity is added. We said in EF 6.x that the EF internal mechanism will automatically call DetectChanges when we call methods such as Add, but the DetectChanges method will no longer be called in EF Core 1.1. Without proof, I downloaded the source code as follows:

Public virtual void Add (TEntity item) {var entry = _ stateManager.GetOrCreateEntry (item); if (entry.EntityState = = EntityState.Deleted | | entry.EntityState = = EntityState.Detached) {OnCountPropertyChanging (); entry.SetEntityState (EntityState.Added); _ count++; OnCollectionChanged (NotifyCollectionChangedAction.Add, item) OnCountPropertyChanged ();}}

We don't see any logic for automatically calling DetectChanges above. In EF 6.x, we mentioned that DetectChanges will be called back when SaveChanges is called, and the same is true in EF Core 1.1, so compared to EF 6.x, EF Core 1.1 only calls DetectChanges when SaveChanges, and does not call DetectChanges in Add, Attacth, Update and other methods, so the performance will be much better. We see the following logic when calling SaveChanges in the source code:

Public virtual int SaveChanges (bool acceptAllChangesOnSuccess) {CheckDisposed (); TryDetectChanges (); try {return StateManager.SaveChanges (acceptAllChangesOnSuccess);} catch (Exception exception) {..}}

Next, let's look at what happens when methods such as Add, Update, and so on are called.

Add: there is nothing to say when the Add method is called, and all the corresponding entities in the diagram are pushed into the Added state, that is, they will be inserted into the database when SaveChanges is called.

Attach: all entities in the diagram are pushed to the UnChanged state when the Attach method is called, but there is an additional case, for example, when we add navigation attribute data to a class, Attach will use mixed mode, the state of the entity is UnChanged and the state of the navigation property is Added, so when inserted into the database, the existing data will not be saved Only the newly added navigation property data will be inserted into the database.

The Update:Update method, like the Attach method, simply changes its state to Modified, and changes to the newly added entity are inserted.

Remove: when the Remove method is called, it only affects the entity passed to the method and does not traverse the reachable graph of the entity. If the status of an entity is UnChanged or Modified, the entity already exists in the database, and you only need to change its status to Deleted. If the status of the entity is Added, it means that the entity does not exist in the database and is out of context and not being tracked. So the Remove method emphasizes that the entity should be tracked, otherwise it needs to be Attach first and then pushed into the Deleted state.

Range method

AddRanges, UpdateRanges and other methods are added in EF Core 1.1, which are the same as calling non-Range methods many times. They also traverse the entity collection and update its state internally, as follows:

Public virtual void UpdateRange ([NotNull] IEnumerable entities) = > SetEntityStates (Check.NotNull (entities, nameof (entities)), EntityState.Modified)

Let's take a look at the implementation of the SetEntityStates method.

Private void SetEntityStates (IEnumerable entities, EntityState entityState) {var stateManager = StateManager; foreach (var entity in entities) {SetEntityState (stateManager.GetOrCreateEntry (entity), entityState);}}

The processing performance of the internal mechanism of EF Core is certainly higher than that of manually traversing and adding entity collections before. I came across an article saying that it is only a little more efficient, because the Range method automatically calls the DetectChanges method, and I haven't seen where to call DetectChanges for a long time. It's a bit of a doubt.

[note] the EF team has been promising that EF Core will be more efficient and scalable, but I read the source code and found that DetectChanges is still called automatically, which is still not very efficient in terms of performance. However, it has been clearly stated in the source code that the api will be changed or completely removed in the future with regard to the DetectChanges method. The source code comments are as follows:

/ This API supports the Entity Framework Core infrastructure and is not intended to be used / directly from your code. This API may change or be removed in future releases. / void DetectChanges ([NotNull] IStateManager stateManager); tracking chart

For change tracking, whether change tracking is enabled by default, we obtain it through the ChangeTracker attribute, as follows:

EFCoreContext efCoreContext; efCoreContext.ChangeTracker.AutoDetectChangesEnabled; efCoreContext.ChangeTracker.DetectChanges

There is also an important method in ChangeTracker that is as follows:

EfCoreContext.ChangeTracker.TrackGraph

Let's call it a trace graph, which has complete control over the state of the entity. For example, if we want to set one of its values to a temporary value before inserting the data into the database, we can do so through this method.

Blog blog; using (var efCoreContext = new EFCoreContext (options)) {efCoreContext.ChangeTracker.TrackGraph (blog, node = > {var entry = node.Entry; if ((int) entry.Property ("Id"). CurrentValue

< 0) { entry.State = EntityState.Added; entry.Property("Id").IsTemporary = true; } else { entry.State = EntityState.Modified; } }); } 在EF Core 1.1其余的就是关于Add、Update等方法的异步操作了,对于操作数据库不至于阻塞的情况也还是挺好的。 EntityFramework Core 1.1方法实践详解 关于EF Core 1.1中一些基本的知识我们过了一遍,下面我们来看看这些方法到底该如何高效使用呢? Add/AddRange 关于这个方法就没有太多叙述的了,对应的则是异步方法。我们重点看看其他的方法。 Update/UpdateRange 当我们根据主键去更新所有实体这个so easy了,我们在Blog表添加如下数据。 (1)更新方式一 现在我们查出Id=1的实体,然后将Name进行修改如下: IBlogRepository _blogRepository; public HomeController(IBlogRepository blogRepository) { _blogRepository = blogRepository; } public IActionResult Index() { var blog = _blogRepository.GetSingle(d =>

D.Id = = 1); blog.Name = "EntityFramework Core 1.1"; _ blogRepository.Commit (); return View ();}

Above, we directly query out the entity corresponding to the primary key, then modify its value, and finally submit and update the corresponding modified attribute of its entity. Finally, the logical data field was modified.

We know that because the queried entity is always tracked without turning off change tracking, changes must be made accordingly, but what if the following is the case.

Public IActionResult Index (int Id,Blog blog) {return Ok ();}

When the data is modified on the client side, we need to modify the corresponding attributes according to the primary key Id. Of course, if we do not want to make unnecessary efforts, we can query the corresponding entities according to the primary key Id, then assign the attributes and finally submit the changes to the database, which will probably evolve into the following situation.

Public IActionResult Index (int Id,Blog blog) {var oldBlog = _ blogRepository.GetSingle (d = > d.Id = = Id); oldBlog.Name = blog.Name; oldBlog.Url = blog.Url; _ blogRepository.Commit (); return Ok ();}

It is true that the above methods can achieve my goal, in fact, there are simple and convenient methods, as follows:

(2) update mode 2

Since there is a simple way why we do not use it, such a scenario is to update the specified properties. In the past, we used to encapsulate a Update method, then use reflection to include the attributes that need to be modified, and then change the status of the attributes to modification, and finally submit the modification. Yes, that's what we're talking about, but there's no need for us to encapsulate it in EF Core 1.1. all we need to do is encapsulate it into a generic method, and the built-in implementation EF Core has been implemented for us, let's take a look.

Void Update (T entity, params Expression [] properties)

If you are familiar with it, we give such an interface in the base warehousing interface, and then we implement this interface, as follows:

Public void Update (T entity, params Expression [] properties) {_ context.Entry (entity). State = EntityState.Unchanged; foreach (var property in properties) {var propertyName = ExpressionHelper.GetExpressionText (property); _ context.Entry (entity) .property (propertyName). IsModified = true;}}

Is it simple and rough enough? open source is good. When you look up the information, you find that the foreigner has given a specific implementation, but when you call it directly, you find that it has been encapsulated for us, and then we modify the specified attribute as follows:

Public IActionResult Index () {var blog = new Blog () {Id = 1, Name = "EntityFramework Core 1.1"}; _ blogRepository.Update (blog, d = > d.Name); _ blogRepository.Commit (); return Ok ();}

The above is only a demonstration, in the actual project, we only need to give our modified primary key and entity. If you are modifying a collection of entities, reload a traversal to ok. Have you found that it is already perfect here, and there is a more perfect solution? please read on.

(3) updating method 3.

In fact, there is a more enjoyable way in ASP.NET Core MVC by using the TryUpdateModelAsync method, which is implemented with multiple overloads and does not require us to encapsulate it at all. As follows:

Public async Task Index () {var blog = _ blogRepository.GetSingle (d = > d.Id = = 1); blog.Name = "EntityFramework Core 1.1"; await TryUpdateModelAsync (blog,", d = > d.Name); _ blogRepository.Commit (); return Ok ();}

Each of the above three update methods has its own application scenarios. If you have to sum up, it is mainly about the choice between the second method and the third method. The second method does not need to be queried by manual encapsulation. You can directly change its status to submit updates, while the third method requires queries to be tracked and finally submitted for updates, depending on which method you think is more appropriate. We're done with data updates in EF Core 1.1. let's take a look at deletions.

Remove/RemoveRange

For the above and update, if the entity has been changed and tracked, you can directly call the built-in method Delete method. In most scenarios, the data is deleted according to the primary key. There are two ways for us to choose from. Please read on.

(1) deletion method 1

Public IActionResult Index () {var blog = _ blogRepository.GetSingle (d = > d.Id = = 1); _ blogRepository.Delete (blog); _ blogRepository.Commit (); return Ok ();}

We query the entity that needs to be deleted, and then delete it by calling the Remove (I encapsulated here) method to mark it as Deleted status. When querying data, we can turn off change tracking. On the one hand, if the amount of data is large, it will not put too much pressure on memory. On the other hand, because calling the Remove method will mark it as Deleted status and will be tracked, there will be no problem.

(2) deletion method 2 [recommended]

In order to minimize the request time, why do we need two steps if we can do it in one step? we can directly instantiate an entity, assign its primary key, change its status to Deleted, and finally persist to the database to delete the corresponding data. As follows:

Public IActionResult Index () {var blog = new Blog () {Id = 1}; _ blogRepository.Delete (blog); _ blogRepository.Commit (); return Ok ();}

Query

Finally, there is one query left to describe, which is the same as adding the method, which is relatively simple and we can go over it a little bit. Since deferred loading is no longer supported in EF Core, we need to explicitly obtain the navigation properties we need through Include, such as the following:

DbContext dbContext; dbContext.Set () .Include (d = > d.Posts)

If there are more than one navigation attribute, let's move on to ThenInclude, as follows:

DbContext dbContext; dbContext.Set (). AsNoTracking (). Include (d = > d.Posts). ThenInclude (d = > d.).

In order to avoid so many ThenInclude, it is convenient to call the following encapsulation:

Public T GetSingle (Expression predicate, params Expression [] includeProperties) {IQueryable query = _ context.Set (); foreach (var includeProperty in includeProperties) {query = query.Include (includeProperty);} return query.Where (predicate). FirstOrDefault ();}

At this point, we only need to make the corresponding call, roughly as follows:

_ blogRepository.GetSingle (d = > d.Id = = 1, p = > p.Posts, p = >....)

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Database

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report