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

How to understand entity classes and warehousing classes in the domain layer of ABP framework

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

Share

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

This article focuses on "how to understand the entity classes and warehousing classes in the domain layer of the ABP framework". Interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn how to understand the entity classes and warehouse classes in the domain layer of the ABP framework.

Domain layer

Entity is one of the core concepts of DDD (domain driven design). Eric Evans describes that "many objects are defined not by their properties, but by a series of consecutive events and identities" (reference to domain-driven design).

Translator's note: objects are not fundamentally defined by their attributes, but by their linear continuity and identification. no, no, no. Therefore, the entity is an ID with a unique identity and is stored in the database. Entities are usually mapped to a table in the database.

Entity class (Entity classes)

In ABP, entities inherit from the Entity class, as shown in the following example:

Public class Person: Entity {public virtual string Name {get; set;} public virtual DateTime CreationTime {get; set;} public Task () {CreationTime = DateTime.Now;}}

The Person class is defined as an entity. It has two properties, and its parent class has the Id attribute. Id is the primary key of the entity. Therefore, Id is the primary key of all entities inherited from the Entity class (the primary key of all entities is the Id field).

Id (primary key) data type can be changed. The default is the int (int32) type. If you want to define other types for Id, you should declare the type of Id as shown in the following example.

Public class Person: Entity {public virtual string Name {get; set;} public virtual DateTime CreationTime {get; set;} public Task () {CreationTime = DateTime.Now;}}

You can set it to string,Guid or other data types.

The entity class overrides the equality (= =) operator to determine whether two entity objects are equal (whether the Id of two entities is equal). An IsTransient () method is also defined to detect whether the entity has an Id attribute.

Interface convention

In many applications, many entities have attributes like CreationTime (this field is also available in database tables) to indicate when the entity was created. APB provides some useful interfaces to implement these similar functions. In other words, a general coding method is provided for these entities that implement these interfaces (generally speaking, as long as the specified interfaces are implemented, the specified functions can be achieved).

(1) Audit (Auditing)

Entity classes that implement the IHasCreationTime interface can have the properties of CreationTime. When the entity is inserted into the database, ABP automatically sets the value of the property to the current time.

Public interface IHasCreationTime {DateTime CreationTime {get; set;}}

The Person class can be overridden to implement the IHasCreationTime interface as in the following example:

Public class Person: Entity, IHasCreationTime {public virtual string Name {get; set;} public virtual DateTime CreationTime {get; set;} public Task () {CreationTime = DateTime.Now;}}

ICreationAudited extends from IHasCreationTime and the interface has the attribute CreatorUserId:

Public interface ICreationAudited: IHasCreationTime {long? CreatorUserId {get; set;}}

When you save a new entity, ABP automatically sets the property value of CreatorUserId to the Id of the current user

You can easily implement the ICreationAudited interface by deriving from the entity class CreationAuditedEntity (because this class already implements the ICreationAudited interface, we can directly inherit the CreationAuditedEntity class to achieve the above functionality). It has a generic version that implements different ID data types (the default is int), and you can assign different data types to ID (ID in the Entity class).

Here is an interface to implement similar modification functions

Public interface IModificationAudited {DateTime? LastModificationTime {get; set;} long? LastModifierUserId {get; set;}}

When you update an entity, ABP automatically sets the values of these properties. You only need to implement these properties in your entity class.

If you want to implement all the audit attributes, you can directly extend the IAudited interface; the example is as follows:

Public interface IAudited: ICreationAudited, IModificationAudited {}

As a rapid development method, you can derive directly from the AuditedEntity class, without the need to implement the IAudited interface (AuditedEntity class has implemented this function, directly inheriting this class can achieve the above functions), AuditedEntity class has a generic version of different ID data types (the default is int), you can give ID (ID in the Entity class) different data types.

(2) soft deletion (Soft delete)

Soft deletion is a general pattern used to mark an entity that has been deleted rather than actually deleting a record from the database. For example, you may not want to delete a user record from the database because it is associated with many other tables. For the purpose of soft deletion, we can implement the interface ISoftDelete:

Public interface ISoftDelete {bool IsDeleted {get; set;}}

ABP implements soft delete mode out of the box. When an entity that has implemented a soft deletion is being deleted, ABP will detect the action and prevent it from being deleted, set the IsDeleted attribute to true and update the entity in the database. In other words, soft deleted records cannot be retrieved from the database, and ABP will automatically filter soft deleted records for us. (for example, a Select query, which here refers to a query through ABP, not through a query analyzer in the database. )

If you use soft deletion, you may also want to implement this function, which is to record who deleted the entity. To achieve this, you can implement the IDeletionAudited interface, as shown in the following example:

Public interface IDeletionAudited: ISoftDelete {long? DeleterUserId {get; set;} DateTime? DeletionTime {get; set;}}

As you can see, IDeletionAudited extends from the ISoftDelete interface. ABP automatically sets values for these attributes when an entity is deleted.

If you want to extend all audit interfaces (such as creation, modification, and deletion) for entity classes, you can implement the IFullAudited interface directly, because it already inherits these interfaces. See the following example:

Public interface IFullAudited: IAudited, IDeletionAudited {}

As a shortcut, you can derive your entity class directly from the FullAuditedEntity class, because the class already implements the IFullAudited interface.

Note: all audit interfaces and classes have a generic template to navigate the definition of attributes to your User entities (for example: ICreationAudited and FullAuditedEntity), where TUser refers to the type of entity class of the user to create, modify and delete, for more information, please see the source code (FullAuditedEntity class in Abp.Domain.Entities.Auditing space), TprimaryKey is only the Entity base class Id type, the default is int.

(3) active / idle state (Active/Passive)

Some entities need to be marked as active or idle. Then you can take the active/passive status action for the entity. For entities created for this reason, you can extend the IPassivable interface to implement this function. This interface defines the properties of the IsActive.

If the entity you created for the first time is marked as active, you can set the IsActive attribute to true in the constructor.

This is different from soft deletion (IsDeleted). If the entity is soft deleted, it cannot be retrieved from the database (ABP has filtered the soft delete record). But for active / idle entities, you all depend on how you get these tagged entities.

IEntity interface

In fact, Entity implements the IEntity interface (and Entity implements the IEntity interface). If you don't want to derive from the Entity class, you can implement these interfaces directly. Other entity classes can also implement the corresponding interfaces. But it is not recommended that you use this way. Unless you have a good reason not to derive from the Entity class.

Storage (Repositories)

Warehouse definition: "mediations in the domain layer and the data mapping layer use collection-like interfaces to access domain objects" (Martin Fowler).

In fact, warehousing is used to manipulate domain objects on the database (entity Entity and value object Value types). In general, we create corresponding repositories for different entities (or aggregate root Aggregate Root).

IRepository interface

In ABP, the repository class implements the IRepository interface. The best way is to define different interfaces for different warehousing objects.

An example of a warehouse interface declaration for a Person entity is as follows:

Public interface IPersonRepository: IRepository {}

IPersonRepository inherits from IRepository and is used to define entities of type int (Int32) of Id. If your entity Id data type is not int, you can inherit the IRepository interface, as shown below:

Public interface IPersonRepository: IRepository {}

For warehouse classes, IRepository defines a number of generic methods. For example: the Select,Insert,Update,Delete method (CRUD operation). Most of the time, these methods are sufficient to meet the needs of general entities. If these parties are sufficient for the entity, we no longer need to create the warehouse interface / class required by the entity. There are more details in the Implementation section.

(1) query (Query)

IRepository defines common methods for retrieving entities from a database.

A. Acquire a single entity (Getting single entity):

TEntity Get (TPrimaryKey id); Task GetAsync (TPrimaryKey id); TEntity Single (Expression predicate); TEntity FirstOrDefault (TPrimaryKey id); Task FirstOrDefaultAsync (TPrimaryKey id); TEntity FirstOrDefault (Expression predicate); Task FirstOrDefaultAsync (Expression predicate); TEntity Load (TPrimaryKey id)

The Get method is used to get the corresponding entity based on the primary key value (Id). It throws an exception when no matching entity is found in the database based on the primary key value. The Single method is similar to the Get method, but its input parameter is an expression rather than a primary key value (Id). Therefore, we can write Lambda expressions to get the entity. Examples are as follows:

Var person = _ personRepository.Get (42); var person = _ personRepository.Single (p = > o.Name = = "Halil ibrahim Kalkan")

Note that the Single method throws an exception when no entity is found or more than one entity is matched for the given condition.

The same goes for FirstOrDefault, but when there is no entity that conforms to the Lambda expression or Id, null is returned (instead of throwing an exception). When more than one entity meets the criteria, it only returns the first entity.

Load does not retrieve entities from the database, but it creates proxy objects needed to delay execution. If you only use the Id attribute, it will not actually retrieve the entity, it will query the entity from the database only when you access an attribute of the entity you want to query. This method can be used as an alternative to the Get method when there is a performance requirement. The Load method is also implemented in the integration of NHibernate and ABP. If the ORM provider (Provider) does not implement this method, the Load method runs the same as the Get method.

Some of the ABP methods are available in Async versions and can be applied to the asynchronous development model (see the section on the Async method).

B. Get the list of entities (Getting list of entities):

List GetAllList (); Task GetAllListAsync (); List GetAllList (Expression predicate); Task GetAllListAsync (Expression predicate); IQueryable GetAll ()

GetAllList is used to retrieve all entities from the database. Overload and provide the ability to filter entities, as follows:

Var allPeople = _ personRespository.GetAllList (); var somePeople = _ personRepository.GetAllList (person = > person.IsActive & & person.Age > 42)

GetAll returns an object of type IQueryable. So we can do the Linq operation after calling this method. Example:

/ / example 1: var query = from person in _ personRepository.GetAll () where person.IsActiveorderby person.Nameselect person;var people = query.ToList (); / / case 2: List personList2 = _ personRepository.GetAll () .Where (p = > p.Name.Contains ("H")) .OrderBy (p = > p.Name) .Skip (40) .Take (20). ToList ()

If you call the GetAll method, almost all queries can be done using Linq. You can even use it to write Join expressions.

Description: about IQueryable

When you call the GetAll method outside the Repository object, the database connection must be opened. This is because IQueryable allows for delayed execution. It won't actually execute the database query until you call the ToList method or use IQueryable on the forEach loop (or some access to queried object methods). Therefore, when you call the ToList method, the database connection must be enabled. We can use the UnitOfWork feature provided by ABP to implement it on the calling method. Notice that the Application Service method presets are already UnitOfWork. Therefore, if you use the GetAll method, you don't need to add the UnitOfWork feature to the Application Service method.

Some methods have asynchronous versions that can be applied to the asynchronous development model (see the section on async methods).

Custom return value (Custom return value)

ABP also has an additional method to achieve the delayed loading effect of IQueryable without the need to add the property volume label UnitOfWork to the called method.

T Query (Func queryMethod)

The query method accepts a Lambda (or a method) to receive the IQueryable and returns any object type. Examples are as follows:

Var people = _ personRepository.Query (Q = > q.Where (p = > p.Name.Contains ("H")) .OrderBy (p = > p.Name). ToList ()

Because it is executed in the method of the storage object using Lambda (or method), it is not executed until the database connection is opened. You can return a collection of entities, or an entity, or a partial field (note: non-Select *) or other query result set after the query has been executed.

(2) add (insert)

The IRepository interface defines a simple method to provide a new entity to the database:

TEntity Insert (TEntity entity); Task InsertAsync (TEntity entity); TPrimaryKey InsertAndGetId (TEntity entity); Task InsertAndGetIdAsync (TEntity entity); TEntity InsertOrUpdate (TEntity entity); Task InsertOrUpdateAsync (TEntity entity); TPrimaryKey InsertOrUpdateAndGetId (TEntity entity); Task InsertOrUpdateAndGetIdAsync (TEntity entity)

The new method adds an entity to the database and returns the same new entity. The InsertAndGetId method returns the identifier (Id) of the new entity. It is very useful when we use automatically incrementing the identifier value and need to get the newly generated identifier value of the entity. InsertOfUpdate adds or updates entities, and which one is chosen based on whether the Id has a value or not. Finally, InsertOrUpdatedAndGetId returns the ID value after the entity is added or updated.

All methods have asynchronous versions that can be applied to the asynchronous development model (see section on asynchronous methods)

(3) update (UPDATE)

IRepository defines a method to update an entity that already exists in the database. It updates the entity and returns the same entity object.

TEntity Update (TEntity entity); Task UpdateAsync (TEntity entity)

(4) delete (Delete)

IRepository defines some ways to delete entities from an existing database.

Void Delete (TEntity entity); Task DeleteAsync (TEntity entity); void Delete (TPrimaryKey id); Task DeleteAsync (TPrimaryKey id); void Delete (Expression predicate); Task DeleteAsync (Expression predicate)

The first method accepts an existing entity, and the second method accepts the Id of the existing entity.

The last method accepts a condition to delete the eligible entity. Note that all entities that conform to the predicate expression are retrieved and then deleted. Therefore, you should be very careful in use, which may cause many problems if there are too many entities that meet the criteria.

All methods have an async version to apply to the asynchronous development model (see the section on asynchronous methods).

(5) other methods (others)

IRepository also provides methods to get the number of entities in the data table.

Int Count (); Task CountAsync (); int Count (Expression predicate); Task CountAsync (Expression predicate); Long LongCount (); Task LongCountAsync (); Long LongCount (Expression predicate); Task LongCountAsync (Expression > predicate)

All methods have async versions that are applied to the asynchronous development model (see the section on asynchronous methods).

(6) about asynchronous methods (About Async methods)

ABP supports the asynchronous development model. Therefore, the warehousing method has an Async version. Here is an example of an application service method that uses an asynchronous model:

Public class PersonAppService: AbpWpfDemoAppServiceBase, IPersonAppService {private readonly IRepository _ personRepository; public PersonAppService (IRepository personRepository) {_ personRepository = personRepository;} public async Task GetAllPeople () {var people = await _ personRepository.GetAllListAsync (); return new GetPeopleOutput {People = Mapper.Map (people)};}}

The GetAllPeople method is asynchronous and uses GetAllListAsync and await to retain keywords.

Async is not available in every ORM framework.

The above example is the asynchronous capability provided from EF. If the ORM framework does not provide Async's warehousing method, it will operate synchronously. Similarly, for example, the InsertAsync operation is the same as the addition of EF, because the EF will not write the new entity to the database (DbContext.SaveChanges) until the unit job (unit of work) is completed.

Realization of warehousing

ABP is designed by not specifying a specific ORM framework or other access database technologies. As long as you implement the IRepository interface, any framework can use it.

It is easy to implement warehousing using NHibernate or EF.

EntityFramework

When you use NHibernate or EntityFramework, if the methods provided are sufficient, you do not need to create a warehouse object for your entity. We can inject IRepository (or IRepository) directly. The following example uses warehouse objects for application service to add entities to the database:

Public class PersonAppService: IPersonAppService {private readonly IRepository _ personRepository; public PersonAppService (IRepository personRepository) {_ personRepository = personRepository;} public void CreatePerson (CreatePersonInput input) {person = new Person {Name = input.Name, EmailAddress = input.EmailAddress}; _ personRepository.Insert (person);}}

The constructor of PersonAppService injects IRepository and uses its Insert method. When you need to create a custom warehouse method for an entity, you should create a warehouse class for the specified entity.

Manage database connections

Database connection is opened and closed, in the warehousing method, ABP will automatically manage the connection.

When the warehousing method is called, the database connection automatically opens and the transaction starts. When the warehousing method finishes and returns, all entity changes are stored, the transaction is committed, and the database connection is closed, all under the control of ABP automation. If the warehousing method throws any type of exception, the transaction is automatically rolled back and the data connection is closed. All of the above operations can be called in all exposed methods of the repository class that implements the IRepository interface.

If warehousing methods call other warehousing methods (even different warehousing methods), they share the same connection and transaction. The connection is managed by the warehouse method at the top of the chain of calls to the warehouse method. For more information on database management, see the UnitOfWork file.

The life cycle of storage

All warehousing objects are temporary. That is to say, they are created only when necessary. ABP uses dependency injection heavily, and when a repository class needs to be injected, the new class reality is automatically created by the injection container. See phase for more information based on the injection file.

Best practices for warehousing

For a T-type entity, you can use IRepository. But don't create customized warehouses under any circumstances unless we really need them. Predefined warehousing methods are sufficient to cope with a variety of cases.

Suppose you are creating a custom warehouse (you can implement IRepository)

The repository class should be stateless. This means that you should not define the state object of the warehouse level and the invocation of the warehouse method should not affect other calls.

When warehousing can be used according to injection, it can be less or not based on other services.

At this point, I believe you have a deeper understanding of "how to understand the entity classes and warehousing classes in the domain layer of the ABP framework". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

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

Development

Wechat

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

12
Report