The application of the data filter in the ABP framework and the use of the transmission object

Source: Internet
Author: User
Tags automap json naming convention require serialization


Data filter (filters)
in database development, we generally use the soft deletion (Soft-delete) mode, that is, not to delete data directly from the database, but to mark this data as deleted. Therefore, if the entity is deleted softly, it should not be retrieved in the application. To achieve this effect, we need to add SQL's where Condition isdeleted = false on each query that retrieves the entity. It's a tedious job, but it's an easy thing to forget. Therefore, we should have an automatic mechanism to deal with these problems.



ABP provides a data filter, which uses automated, rule-based filtering queries. ABP already has some predefined filters, and of course you can create your own filters.



Note: Only ENTITYFRAMEWORK:ABP data filters are implemented in EntityFramework. It is not available in other ORM tools. See other ORM Chapters at the end of this article.



Predefined filters
1. Soft deletion interface (Isoftdelete)



The Soft deletion filter (Soft-delete filter) filters the entities that are queried from the database and is automatically applied (extracted from the result set). If the entity needs to be soft removed, it needs to implement the Isoftdelete interface, which defines only one isdeleted attribute. Cases:


 public class Person:entity, Isoftdelete {public
 virtual string Name {get; set;}
 Public virtual bool IsDeleted {get; set;}
 }


The person entity is not actually deleted from the database, and when this entity is deleted, the IsDeleted property value is set to true. When you use the Irepository.delete method, ABP automatically completes the work (you can manually set IsDeleted to True, but the Delete method is more natural and more recommended).



When the Isoftdelete is implemented, when you have obtained the People list from the database, the deleted people entity is not retrieved. Here is an example class that uses the person repository to get all the people entities:


 public class MyService {
 private readonly irepository<person> _personrepository;

 Public MyService (irepository<person> personrepository) {
  _personrepository = personrepository;
 }

 Public list<person> Getpeople () {return
  _personrepository.getalllist ();
 }
 }


The Getpeople method only obtains the person entity whose isdeleted = False (not the deletion state). All warehousing methods and navigation properties are functional. We can add some other where conditions, Join ... Wait a minute. It will automatically add isdeleted=false conditions to the generated SQL query statement.



Note: When is it enabled? The Isoftdelete filter is always enabled unless you disable it directly.



Reminder: If you implement the Ideletionaudited interface (which inherits from Isoftdelete), delete the creation time and the deleted user ID, which will be automatically processed by the ABP.



2. Multi-Rent Interface (imusthavetenant)



If you create a multi-tenant application that stores all of the tenant's data in a single database, you certainly don't want a tenant to see other tenants ' information. You can implement the Imusthavetenant interface in this case, as shown in the following example:


 public class Product:imusthavetenant {public
 virtual int Tenantid {get; set;}

 Public virtual string Name {get; set;}
 }


Imusthavetenant defines tenantid to differentiate between different tenant entities. ABP uses iabpsession to get the current Tenantid and automatically filter queries for the current tenant.



Note: When is it enabled? Imusthavetenant is enabled by default. If the current use is not logged into the system or the current user is an admin-level consumer (the admin-class consumer is a user with the highest authority, it can manage all the tenant and tenant data), ABP automatically disables the Imusthavetenant filter. As a result, all tenant data can be retrieved by the application. Note that this has nothing to do with security, and you should verify that sensitive data is authorized to be processed.



3. Multi-Rent Interface (imayhavetenant)



If an entity class is shared by multiple tenants (tenant) and an administrative user (host) (which means that the entity object may be controlled by a tenant (tenant) or an administrative user (host)), you can use Imayhavetenantfilter. The Imayhavetenant interface defines Tenantid but it is a nullable class (nullable).


 public class Product:imayhavetenant {public
 virtual int? Tenantid {get; set;}

 Public virtual string Name {get; set;}
 }


A null value means that this is an entity controlled by an administrative user (host) and, if it is a non-null value, that the entity is controlled by the tenant (tenant) and its ID value is Tenantid. ABP uses the Iabpsession interface to obtain the current tenantid. Imayhavetenant filters are not commonly used as imusthavetenant. However, you may need to use it when used as a common structure required by the administrative user (host) and Tenant (tenant).



When is it enabled? The Imayhavetenant interface is always enabled unless you disable it directly.



Disable Filter
You can disable a filter by calling the Disablefilter method in the unit of work, as follows:


var people1 = _personrepository.getalllist ();
Using (_unitofworkmanager.current.disablefilter (Abpdatafilters.softdelete)) {
 var people2 = _ Personrepository.getalllist ();
 }

var people3 = _personrepository.getalllist ();


The Disablefilter method obtains one or more filter names and is of type string. Abpdatafilters.softdelete is a constant string containing the ABP standard soft delete filter.



People2 can also obtain people entities that have been marked for deletion, and People1 and People3 will be the only people entities that are not marked for deletion. If you use the using syntax, you can disable the filter within its control (scope). If you do not use the using syntax, this filter is disabled until the unit of work ends or it is enabled again. (meaning: If you use the "using" keyword to declare that the filter is enabled, the filter is disabled after the current unit of work is terminated). If you do not declare using the "using" keyword, the default filter is disabled, and you can enable the filter manually at this time. )



You can inject Iunitofworkmanager and use it in the example above. Similarly, you can use the Currentunitofwork property as an easy way to apply a service (it inherits from the Applicationservice Class).



Note: About the Using syntax: If the filter is enabled before you call the Disablefilter method and with the using syntax, the filter is disabled and automatically enabled at the end of the using syntax. However, if the filter has been disabled before using syntax, the Disablefilter method does not actually do anything, and the filter maintains a disabled state even after the end of the using syntax.



Enable Filter
You can use the Enablefilter method in the unit of work to enable filters, as in the Disablefilter method (both sides of each other). Enablefilter will also return disposable to automatically disable the filter again.



Set Filter Parameters
filters can be parameterized (parametric). The Imusthavetenant filter is a template for this type of filter because the ID of the current tenant (tenant) is determined during the execution period. For these filters, we can change the value of the filter if it is necessary. Examples are as follows:



Currentunitofwork.setfilterparameter ("Personfilter", "PersonId", 42);
Another example is the following: Set the Tenantid value of the Imayhavetenant filter:



CurrentUnitOfWork.SetfilterParameter(AbpDataFilters.MayHaveTenant, AbpDataFilters.Parameters.TenantId, 42);


Custom Filters
to create a custom filter and integrate it into ABP, we first need to define an interface that will be implemented by the entity that uses the filter. Let's say we want to automate filtering by PersonID, as shown in the following example:
 Public interface Ihasperson {
 int PersonId {get; set;}
 }


We can then implement this interface on our entity, as shown in the following example:


 public class phone:entity, Ihasperson {
 [ForeignKey ("PersonId ')] ' public virtual person person '
 {get; set;} Public

 Virtual int PersonId {get; set;}

 Public virtual string Number {get; set;}
 }


Because ABP uses the Entityframework.dynamicfilters filter, we use its rules (rule) to define the filter. In our DbContext class, we rewrote the onmodelcreating and defined the filter as shown in the following example:


 protected override void Onmodelcreating (Dbmodelbuilder modelbuilder) {
 base. Onmodelcreating (ModelBuilder);
 Modelbuilder.filter ("Personfilter", (ihasperson entity, int personId) => entity. PersonId = = PersonId, 0);
 }


The Personfilter filter here is a unique filter name. Then again is the filter interface parameter definition and PersonID filter parameters (not necessarily, if the filter is not parameterized (parametric) type), the last parameter is the default value of PersonID.



In the final step, we need to register this filter into the ABP work unit (work) system, set the position in our module Preinitialize method.


Configuration.UnitOfWork.RegisterFilter ("Personfilter", false);


The first argument is the unique name we just defined, and the second parameter indicates whether the filter preset is enabled or disabled. After declaring these parameterized (parametric) filters, we can specify its value during execution to manipulate this filter.


 using (Currentunitofwork.enablefilter ("Personfilter")) {
 currentunitofwork.setfilterparameter ("PersonFilter") , "PersonId",);
 var phone = _phonerepository.getalllist ();
 // ...
 }


We can get PersonID from some data sources without having to write dead in the program code. The example above is to be able to programmatically filter. The filter can have 0 to more parameters. If it is a filter without parameters, it does not need to set the value of the filter. Similarly, if it is enabled, it does not need to be manually enabled (we can also disable it, of course).



Entityframework.dynamicfilters files: If you need more information about Dynamic Data filters, you can see their files on git https://github.com/jcachat/ Entityframework.dynamicfilters



We can create a custom filter for security, primary/passive entities, multiple tenants ... and whatnot.



Other Object Relational mapping tools
The ABP Data filter is implemented only on the Entity Framework. For other ORM tools, it is not yet available. But, in fact, you can emulate this pattern to other cases where data is obtained by using a warehouse. In this case, you can create a custom warehouse and overwrite the GetAll method, and if necessary, modify other data retrieval methods together.




Data Transfer object (DTOs)
Data Transfer objects (data Transfer Objects) are used for data transmission at the application layer and the presentation layer.



The presentation layer incoming data Transfer object (DTO) invokes an application service method, and then the application service executes some specific business logic through the domain object and returns the DTO to the presentation layer. So the presentation layer and the domain layer are completely separated. In applications with a good layering, the presentation layer does not directly use domain objects (warehouses, entities).



The role of data transfer objects
creating a DTO for each application service method appears to be a tedious and time-consuming task. But if you use them correctly, it will save your project. Why, then?



1. Abstract domain layer (abstraction of domain layer)



The data Transfer object in the presentation layer is an effective abstraction of the domain object. This way your layer (layers) will be properly isolated. Even when you want to completely replace the presentation layer, you can continue to use the existing application layer and domain layer. Conversely, you can rewrite the domain layer, modify the database structure, entity, and ORM Framework, but do not need to make any changes to the presentation layer, as long as your application layer does not change.



2. Data hiding (hiding)



Imagine that you have a user entity that has attribute IDs, Name, EmailAddress, and password. If the return value type of the GetAllUsers () method for Userappservice is list. So anyone can view the password for everyone, even if you don't print it on the screen. This is not just a security issue, it's also related to data hiding. Application services should only return to the presentation layer required, not many more just good.



3. Serialization & Lazy Loading (serialization & lazy load problems)



When you return data (objects) to the presentation layer, the data is likely to be serialized. For example, in an MVC action that returns JSON, your object needs to be serialized as JSON and sent to the client. Returning the entity directly to the presentation layer is likely to cause trouble.



In real projects, entities refer to other entities. The user entity references the role entity. So, when you serialize user, role will also be serialized. And the role also has a list and permission also quotes Permissiongroup and so on ... can you imagine that these objects will all be serialized? This has the potential to cause the entire database data to be accidentally serialized. So how to solve it? Mark a property as not serializable? No, because you don't know when the attribute should be serialized and when it should not be serialized. So in this case, the return of a safe serialization, specially customized data transfer object is a good choice oh.



Almost all ORM frameworks support lazy loading. It will only be loaded if you need to load the entity. For example, the user type refers to the role type. When you get user from the database, the role attribute is not populated. The role is loaded from the database the first time you read the role attribute. So, when you return such an entity to the presentation layer, it can easily cause side effects (loaded from the database). If the serialization tool reads the entity, it will read all the attributes recursively so that your entire database will be read.



There are more problems with using entities in the presentation layer. The best scenario is that the presentation layer should not refer to any assembly that contains a domain layer.



DTO Conventions & Validation
ABP provides strong support for data transfer objects. It provides a number of related (conventional) types & interfaces and provides recommendations for DTO naming and usage conventions. Using DTO,ABP as you do here will automate some tasks to make you more relaxed.



An example (Example)



Let's look at a complete example. We're going to write an application service method that searches for people based on name and returns the People list. The person entity code is as follows:


public class person:entity
{public
 virtual string Name {get; set;}
 Public virtual string EmailAddress {get; set;}
 Public virtual string Password {get; set;}
}


First, we define an application service interface:


Public interface Ipersonappservice:iapplicationservice
{
 searchpeopleoutput searchpeople ( Searchpeopleinput input);
}


ABP recommends that named Input/ouput objects resemble Methodnameinput/methodnameoutput, and each application service method needs to be defined separately for input and output. Even if your method only receives or returns a value, it is best to create the appropriate DTO type. In this way, your code will be more extensible, you can add more properties without changing the signature of the method, which does not destroy the existing client application.



Of course, the method return value may be void, and then you add a return value that does not break the existing application. If your method does not require any parameters, then you do not need to define an input Dto. But creating an input dto might be a better solution, because the method might require a parameter in the future. Of course whether to create it depends on you. The input and output DTO types are defined as follows:


 public class Searchpeopleinput:iinputdto
{
 [stringlength (+ minimumlength = 1)] public
 string searchedname {get; set;}
}

public class Searchpeopleoutput:ioutputdto
{public
 list<persondto> people {get; set;}
}

public class Persondto:entitydto
{public
 string Name {get; set;}
 public string EmailAddress {get; set;}
}


Validation: As a convention, Input DTO implements Iinputdto interface, Output DTO implements Ioutputdto interface. When you declare the iinputdto parameter, ABP will automatically validate the method before it is executed. This is similar to the asp.net MVC validation mechanism, but note that the application service is not a controller (Controller). ABP it to intercept and check the input. View the DTO validation (DTO Validation) document for more information. Entitydto is a simple type that has the same ID attribute as an entity. If your Entity ID is not an int, you can use its generic version. Entitydto also implements the Idto interface. You can see that persondto does not contain the password attribute because the presentation layer does not need it.



And before we go further we realize Ipersonappservice:


public class Personappservice:ipersonappservice
{
 private readonly ipersonrepository _personrepository;

 Public Personappservice (ipersonrepository personrepository)
 {
 _personrepository = personrepository;
 }
 Public searchpeopleoutput searchpeople (searchpeopleinput input)
 {
 //Get entity
 var peopleentitylist = _ Personrepository.getalllist (person => person. Name.contains (input. Searchedname));

 Convert to Dto
 var peopledtolist = peopleentitylist
  . Select (person => new persondto
    {
     Id = person. Id,
     Name = person. Name,
     emailaddress = person. EmailAddress
    }). ToList ();

 return new Searchpeopleoutput {people = peopledtolist};
 }



We retrieve the entity from the database, convert the entity to a DTO, and return output. Note that we do not manually detect input data validation. ABP will automatically validate it. ABP even checks whether the input is null and throws an exception if it is null. This avoids the fact that we check the validity of the data manually in each method.



But you probably don't like to manually convert a person entity into a persondto. It's really a boring job. This is especially true when the Peson entity contains a large number of properties.



Automatic mapping between a DTO and an entity
Fortunately, there are some tools that make mapping (transformation) very simple. AutoMapper is one of them. You can add it to your project by NuGet. Let's use AutoMapper to rewrite the Searchpeople method:


Public searchpeopleoutput searchpeople (searchpeopleinput input)
{
 var peopleentitylist = _ Personrepository.getalllist (person => person. Name.contains (input. Searchedname));
 return new Searchpeopleoutput {people = mapper.map<list<persondto>> (peopleentitylist)};
}


That's the whole code. You can add more attributes to the entity and DTO, but the conversion code remains unchanged. There's only one thing you need to do before this: map


Mapper.createmap<person, persondto> ();


AutoMapper created the mapped code. In this way, dynamic mapping is not a performance issue. It's fast and convenient. AutoMapper creates a persondto based on the person entity and assigns a value to Persondto's properties based on the naming convention. The naming conventions are configurable and flexible. You can also customize the mapping and use more features to view AutoMapper documents for more information.



Using attributes (attributes) and extension methods to map (Mapping using Attributes and extension methods)



ABP provides several attributes and extension methods to define mappings. Using it you need to add Abp.automapper to your project via NuGet. There are two ways to map using the Automap feature (attribute), one of which is to use Automapfrom and Automapto. The other is to use the Mapto extension method. Examples of defining mappings are as follows:


[Automap (typeof (MyClass2))]//define mappings (so there are two ways to map) public
class MyClass1
{public
 string Testprop {get; set;}
}

public class MyClass2
{public
 string Testprop {get; set;}
}


You can then use the Mapto extension method to map:


var obj1 = new MyClass1 {testprop = "Test value"};
var obj2 = obj1. Mapto<myclass2> (); A new MyClass2 object is created and is obj1. The Testprop value is assigned to the Testprop property of the new MyClass2 object.


The code above creates a new MyClass2 object based on MyClass1. You can also map objects that already exist, as follows:


var obj1 = new MyClass1 {testprop = "Test value"};
var obj2 = new MyClass2 ();
Obj1. Mapto (OBJ2); Set OBJ2 properties based on Obj1


Secondary interfaces and types
ABP also provides a number of secondary interfaces that define common standardized properties.



Ilimitedresultrequest defines the Maxresultcount property. So you can implement the interface on your input dto to limit the number of result sets.



Ipagedresultrequest extends Ilimitedresultrequest, which adds the Skipcount attribute. So we implement this interface in Searchpeopleinput for paging:


public class Searchpeopleinput:iinputdto, ipagedresultrequest
{
 [stringlength (minimumlength = 1)]
 public string Searchedname {get; set;}

 public int Maxresultcount {get; set;}
 public int Skipcount {get; set;}
}


For paging requests, you can return the output dto that implements Ihastotalcount as the result. Standardized properties help us create reusable code and specifications. You can view additional interfaces and types under the Abp.Application.Services.Dto namespace.


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.