Research on Using Bidirectional Correlation Models in Network Applications

       Building a model is a crucial step when developing a web application. With the development of modeling tools and software, more and more software use bidirectional correlation model for modeling. This paper mainly discusses the advantages of bidirectional correlation model compared with traditional unidirectional model.

       The main difference between the two-way correlation model and the one-way model is that it dynamically describes the interaction between the models: the traditional single-item model only pays attention to the state change of the current model, and does not immediately consider the impact on the environment after its own state change; The two-way correlation model immediately informs other models affected by the change after each change of the current model state, that is, we change not a single model but the entire environment in each operation, because these models are interrelated. are related by a one-to-many or many-to-one relationship.

       The most convenient way to generate a bidirectional correlation model is with the help of the PowerDesigner tool. For example, if we need to model a scenario with a person and a role, a person can have multiple roles, and multiple people can have the same role. This is a typical many-to-many relationship, so the result of modeling with PowerDesigner would look like this:

(Person model has primary key id and name name, Role model has primary key id and description, PersonRole model has primary key id and two foreign keys personId and roleId, where personId is associated with Person's primary key id, and roleId is associated with Role's primary key id. )

​After generating the Java code from the   Because in reality our objects are loaded from the database, in order to allow these objects with different addresses in memory to be "equal" or "unequal" in business logic, we redefine the hashCode of the model object by using ( ), equals(), and using java.util.LinkedHashSet as the method of collection implementation (if the business does not care about the order of objects in the collection, you can use java.util.HashSet instead of java.util.LinkedHashSet, which can further improve performance), we wrap the above features into a generic class PojoSupport and use it as the base class for all model objects. The final code is (the following code is obtained by simply modifying the code automatically generated by PowerDesigner):

package myPackage;

public abstract class PojoSupport<T extends PojoSupport<T>> {

	abstract public Object getId();

	@Override
	/* 重新定义hash方法 */
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
		return result;
	}

	@Override
	/* 重新定义equals方法 */
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		PojoSupport<?> other = (PojoSupport<?>) obj;
		if (getId() == null) {
			return false;
		} else if (!getId().equals(other.getId()))
			return false;
		return true;
	}
}
package myPackage;

public class Person extends PojoSupport<Person> {
	public Person(Integer id, String name) {
		this.id = id;
		this.name = name;
	}

	private Integer id;
	private java.lang.String name;
	private java.util.Collection<PersonRole> personRole;

	public java.util.Collection<PersonRole> getPersonRole() {
		if (personRole == null) {
			personRole = new java.util.LinkedHashSet<PersonRole>();
		}
		return personRole;
	}

	public java.util.Iterator<PersonRole> getIteratorPersonRole() {
		if (personRole == null) {
			personRole = new java.util.LinkedHashSet<PersonRole>();
		}
		return personRole.iterator();
	}

	public void setPersonRole(java.util.Collection<PersonRole> newPersonRole) {
		removeAllPersonRole();
		for (java.util.Iterator<PersonRole> iter = newPersonRole.iterator(); iter.hasNext();) {
			addPersonRole((PersonRole) iter.next());
		}
	}

	public void addPersonRole(PersonRole newPersonRole) {
		if (newPersonRole == null) {
			return;
		}
		if (this.personRole == null) {
			this.personRole = new java.util.LinkedHashSet<PersonRole>();
		}
		if (!this.personRole.contains(newPersonRole)) {
			this.personRole.add(newPersonRole);
			newPersonRole.setPerson(this);
		} else {
			for (PersonRole temp : this.personRole) {
				if (newPersonRole.equals(temp)) {
					if (temp != newPersonRole) {
						removePersonRole(temp);
						this.personRole.add(newPersonRole);
						newPersonRole.setPerson(this);
					}
					break;
				}
			}
		}
	}

	public void removePersonRole(PersonRole oldPersonRole) {
		if (oldPersonRole == null) {
			return;
		}
		if (this.personRole != null) {
			if (this.personRole.contains(oldPersonRole)) {
				for (PersonRole temp : this.personRole) {
					if (oldPersonRole.equals(temp)) {
						if (temp != oldPersonRole) {
							temp.setPerson((Person) null);
						}
						break;
					}
				}
				this.personRole.remove(oldPersonRole);
				oldPersonRole.setPerson((Person) null);
			}
		}
	}

	public void removeAllPersonRole() {
		if (personRole != null) {
			PersonRole oldPersonRole;
			for (java.util.Iterator<PersonRole> iter = getIteratorPersonRole(); iter.hasNext();) {
				oldPersonRole = (PersonRole) iter.next();
				iter.remove();
				oldPersonRole.setPerson((Person) null);
			}
			personRole.clear();
		}
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public java.lang.String getName() {
		return name;
	}

	public void setName(java.lang.String name) {
		this.name = name;
	}
}
package myPackage;

public class Role extends PojoSupport<Role> {
	public Role(Integer id, String description) {
		this.id = id;
		this.description = description;
	}

	private Integer id;
	private java.lang.String description;
	private java.util.Collection<PersonRole> personRole;

	public java.util.Collection<PersonRole> getPersonRole() {
		if (personRole == null) {
			personRole = new java.util.LinkedHashSet<PersonRole>();
		}
		return personRole;
	}

	public java.util.Iterator<PersonRole> getIteratorPersonRole() {
		if (personRole == null) {
			personRole = new java.util.LinkedHashSet<PersonRole>();
		}
		return personRole.iterator();
	}

	public void setPersonRole(java.util.Collection<PersonRole> newPersonRole) {
		removeAllPersonRole();
		for (java.util.Iterator<PersonRole> iter = newPersonRole.iterator(); iter.hasNext();) {
			addPersonRole((PersonRole) iter.next());
		}
	}

	public void addPersonRole(PersonRole newPersonRole) {
		if (newPersonRole == null) {
			return;
		}
		if (this.personRole == null) {
			this.personRole = new java.util.LinkedHashSet<PersonRole>();
		}
		if (!this.personRole.contains(newPersonRole)) {
			this.personRole.add(newPersonRole);
			newPersonRole.setRole(this);
		} else {
			for (PersonRole temp : this.personRole) {
				if (newPersonRole.equals(temp)) {
					if (temp != newPersonRole) {
						removePersonRole(temp);
						this.personRole.add(newPersonRole);
						newPersonRole.setRole(this);
					}
					break;
				}
			}
		}
	}

	public void removePersonRole(PersonRole oldPersonRole) {
		if (oldPersonRole == null) {
			return;
		}
		if (this.personRole != null) {
			if (this.personRole.contains(oldPersonRole)) {
				for (PersonRole temp : this.personRole) {
					if (oldPersonRole.equals(temp)) {
						if (temp != oldPersonRole) {
							temp.setRole((Role) null);
						}
						break;
					}
				}
				this.personRole.remove(oldPersonRole);
				oldPersonRole.setRole((Role) null);
			}
		}
	}

	public void removeAllPersonRole() {
		if (personRole != null) {
			PersonRole oldPersonRole;
			for (java.util.Iterator<PersonRole> iter = getIteratorPersonRole(); iter.hasNext();) {
				oldPersonRole = (PersonRole) iter.next();
				iter.remove();
				oldPersonRole.setRole((Role) null);
			}
			personRole.clear();
		}
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public java.lang.String getDescription() {
		return description;
	}

	public void setDescription(java.lang.String description) {
		this.description = description;
	}
}
package myPackage;

public class PersonRole extends PojoSupport<PersonRole> {

	private Integer id;

	private Person person;

	private Role role;

	public Person getPerson() {
		return person;
	}

	public void setPerson(Person newPerson) {
		if (this.person == null || this.person != newPerson) {
			if (this.person != null) {
				Person oldPerson = this.person;
				this.person = null;
				oldPerson.removePersonRole(this);
			}
			if (newPerson != null) {
				this.person = newPerson;
				this.person.addPersonRole(this);
			}
		}
	}

	public Role getRole() {
		return role;
	}

	public void setRole(Role newRole) {
		if (this.role == null || this.role != newRole) {
			if (this.role != null) {
				Role oldRole = this.role;
				this.role = null;
				oldRole.removePersonRole(this);
			}
			if (newRole != null) {
				this.role = newRole;
				this.role.addPersonRole(this);
			}
		}
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}
}

    The above is a two-way correlation implementation of a many-to-many relationship using the Java language. In this implementation, we use java.util.LinkedHashSet instead of other common collection classes as the carrier container, because java.util.LinkedHashSet can easily and efficiently implement comparison by redefining the equals and hashCode methods to query objects from the database "Equality and inequality in business logic", and it is based on linked list implementation, so the elements are arranged in an orderly manner, and these features will bring us great benefits when actually developing software.

Advantages of Bidirectional Correlation Models

      The relevant code of the model has been given, and we can test the effect of this model through a use case. We define three people (A, B, C) and two roles (admin, user), where A is an administrator, B is a user, and C is both an administrator and a user. The implementation is as follows (for the sake of simplicity and clarity, we assume that the Person class has a constructor for new Person(Integer id, String name) and the Role class has a constructor for new Role(Integer id, String description):

Person p1 = new Person(1, "甲"), p2 = new Person(2, "乙"), p3 = new Person(3, "丙");
Role r1 = new Role(1, "管理员"), r2 = new Role(2, "用户");
PersonRole p1r1 = new PersonRole(), p2r2 = new PersonRole(), p3r1 = new PersonRole(), p3r2 = new PersonRole();

The following code realizes the association between the three personnel A, B, and C and the two roles of administrator and user in 4 different ways:

/* 姓名为甲的人员具有管理员角色 */
p1r1.setPerson(p1);
p1r1.setRole(r1);

/* 姓名为乙的人员具有用户角色 */
p2.addPersonRole(p2r2);
p2r2.setRole(r2);

/* 姓名为丙的人员具有管理员角色 */
p3r1.setPerson(p3);
r1.addPersonRole(p3r1);

/* 姓名为丙的人员也具有用户角色 */
p3.addPersonRole(p3r2);
r2.addPersonRole(p3r2);

      This shows that in a two-way correlation model, the same result can be obtained by calling different methods of different models. And we can choose the most accessible object to operate, which can reduce the number of queries to the database in many cases, and at the same time make the cost of maintaining business data consistency very low.

      If we want to achieve separation between object relationships, such as making user A no longer have the administrator role, there is more than one way to achieve it:

p1.removePersonRole(p1r1);
r1.removePersonRole(p1r1);

/* 或者是 */
p1r1.setPerson(null);
p1r1.setRole(null);

/* 或者是 remove 和 set(null) 的交叉组合 */

      The results of the execution of the above methods are exactly the same, and the user A (p1) and the administrator (r1) are disconnected from the association. Which way to choose in actual development depends on which object is easier for us to get.

      In the one-way model, we need to manually add the code that affects the associated object after the object changes, while the object of the two-way correlation model will immediately affect the associated object after the object changes, and each object will change immediately, and it is implemented at the model level. The business layer can directly use these features without adding any code at all, which is very helpful for us to develop stable and complex network applications.

      The advantages of the two-way correlation model are not only reflected in additions, deletions, and modifications, but also unique in displaying data. Still in the above use case, C (p3) is both an administrator (r1) and a user (r2). Let's serialize C, administrator, and user into json (the FastJson middleware is used here to serialize, Because the objects of the bidirectional correlation model will contain circular references, circular processing must be turned on during serialization. At the same time, the prettyFormat feature of FastJson is also turned on to make the output results easier to read):

The serialized json of user "C" is:

{
    "id" : 3,
	"name" : "丙",
	"personRole" : [{
		"person" : {"$ref" : "$"},
		"role" : {
			"description" : "管理员",
			"id" : 1,
			"personRole" : [{"$ref" : "$.personRole[0]" }]
		}
	},{
		"person" : {"$ref" : "$"},
		"role" : {
			"description" : "用户",
			"id" : 2,
			"personRole" : [{"$ref" : "$.personRole[1]" }]
		}
	}]
}

 The serialized json of the role "admin" is:

{
    "description" : "管理员",
    "id" : 1,
    "personRole" : [{
        "person" : {
            "id" : 3,
            "name" : "丙",
            "personRole" : [ {"$ref" : "$.personRole[0]" },{
	            "person" : { "$ref" : "$.personRole[0].person"},
	            "role" : {
		            "description" : "用户",
		            "id" : 2,
		            "personRole" : [{"$ref" : "$.personRole[0].person. personRole[1]" }]
                }
            }]
        },
		"role" : { "$ref" : "$"}
	}]
}

The serialized json of the role "user" is:

{
	"description" : "用户",
	"id" : 2,
	"personRole" : [{
		"person" : {
			"id" : 3,
			"name" : "丙",
			"personRole" : [{
				"person" : {"$ref" : "$.personRole[0].person"},
				"role" : {
					"description" : "管理员",
					"id" : 1,
					"personRole" : [{"$ref" : "$.personRole[0].person.personRole[0]"}]
                }
            },{"$ref" : "$.personRole[0]"}]
		},
		"role" : {"$ref" : "$"}
    }]
}

      ​The $ref in the above json represents a reference, and $ represents itself. This is an unofficial convention expression in the json grammar. It is used to describe the serialization of objects with circular references. The mainstream javascript frameworks have the ability to parse this. The function of json can also be achieved through javascript native syntax. Taking the json of user "C" as an example, the personJson obtained after parsing has the following characteristics:

personJson.id = 3;
personJson.name = "丙";
personJson.personRole [0].person = personJson; /* 表明对象是可以自引用的 */
personJson.personRole [0].role.description = "管理员";
personJson.personRole [0].role.id = 1;
personJson.personRole [0].role.personRole [0] = personJson.personRole [0];
personJson.personRole [1].person = personJson;
personJson.personRole [1].role.description = "用户";
personJson.personRole [1].role.id = 2;
personJson.personRole [1].role.personRole [0] = personJson.personRole [1];

      If the role "administrator" is taken as an example, the roleJson obtained after parsing has the following characteristics:

roleJson.description = "管理员";
roleJson.id = 1;
roleJson.personRole [0].person.id = 3;
roleJson.personRole [0].person.name = "丙";
roleJson.personRole [0].person.personRole [0] = roleJson.personRole [0];
roleJson.personRole [0].person.personRole [1].person = roleJson.personRole [0].person
roleJson.personRole [0].person.personRole[1].role.description = "用户";
roleJson.personRole [0].person.personRole [1].role.id = 2;
roleJson.personRole [0].person.personRole [1].role.personRole [0] = roleJson.personRole [0].person.personRole [1]
roleJson.personRole [0].role = roleJson; /* 表明对象是可以自引用的 */

​ And if the role "user" is taken as an example, the roleJson obtained after parsing has the following characteristics:

roleJson.description = "用户";
roleJson.id = 2;
roleJson.personRole [0].person.id = 3;
roleJson.personRole [0].person.name = "丙";
roleJson.personRole [0].person.personRole [0].person = roleJson.personRole [0].person;
roleJson.personRole [0].person.personRole[0].role.description = "管理员"; /* 因为“管理员”先于“用户”加入,所以管理员序列化后“管理员”排在“用户”前 */
roleJson.personRole [0].person.personRole [0].role.id = 1;
roleJson.personRole [0].person.personRole [0].role.personRole [0] = roleJson.personRole [0].person.personRole [0];
roleJson.personRole [0].person.personRole [1] = roleJson.personRole [0];
roleJson.personRole [0].role = roleJson; /* 表明对象是可以自引用的 */

      It can be seen from the above that the amount of information contained in the serialized json form of the three is the same, that is to say, in the bidirectional correlation model, we can serialize the most easily obtained object, and its json will automatically contain all the It has the information of related objects (and related objects of related objects), and then performs various processing on json without worrying about losing information, so we can say that the objects of the two-way related model can be easily "aggregated", and because the data Self-referencing (compression) also saves valuable bandwidth space in transit.

      In reality, we can automatically load the "many-to-one" relationship, and manually load the "one-to-many" relationship as needed to avoid the aggregated objects being too large.

Disadvantages of the Bidirectional Correlation Model

    The two-way correlation model requires more code than the one-way model. For example, addPersonRole, removePersonRole, and removeAllPersonRole do not need to be specified in the one-way model, but they need to be strictly defined in the two-way correlation model, and the setter methods such as setPersonRole and setRole are implemented. Also more complex than a one-way model, but we can use modeling tools to automatically generate model code. However, the real problems don't stop there.

      Taking the Java language as an example, the code of the two-way related model needs to be compiled at the same time for all model classes, which is not difficult to do in the current development tools, but if we use Maven to manage the project, considering the scalability of the project, different business Problems arise when modules are placed in different Maven modules. Because Maven modules do not support circular dependencies (ie, module A depends on B and module B also depends on A), although the plugin build-helper-maven-plugin can be used to achieve simultaneous compilation of such modules, Maven itself does not encourage this. Do. When developing a project, in order to build modules that can be compiled without plugins, we need to re-introduce interfaces into the bidirectional correlation model. Still taking the above three models as an example, we create two new packages: packageA and packageB. In packageA, we store the Role class and some interfaces. In packageB, we store the Person class, PersonRole class, and some interfaces. The classes in packageA do not call packageB at all. classes in packageB, and classes in packageB call classes in packageA, simulating a one-way dependency between two Maven modules.

      The code in packageA is as follows:

package myPackageA;

public interface PersonRoleFace {

	void setRole(Role role);

}
package myPackageA;

public class Role extends PojoSupport<Role> {
	public Role(Integer id, String description) {
		this.id = id;
		this.description = description;
	}

	private Integer id;
	private java.lang.String description;
	private java.util.Collection<PersonRoleFace> personRole;

	public java.util.Collection<PersonRoleFace> getPersonRole() {
		if (personRole == null)
			personRole = new java.util.LinkedHashSet<PersonRoleFace>();
		return personRole;
	}

	public java.util.Iterator<PersonRoleFace> getIteratorPersonRole() {
		if (personRole == null)
			personRole = new java.util.LinkedHashSet<PersonRoleFace>();
		return personRole.iterator();
	}

	public void setPersonRole(java.util.Collection<? extends PersonRoleFace> newPersonRole) {
		removeAllPersonRole();
		for (java.util.Iterator<? extends PersonRoleFace> iter = newPersonRole.iterator(); iter.hasNext();)
			addPersonRole((PersonRoleFace) iter.next());
	}

	public void addPersonRole(PersonRoleFace newPersonRole) {
		if (newPersonRole == null)
			return;
		if (this.personRole == null)
			this.personRole = new java.util.LinkedHashSet<PersonRoleFace>();
		if (!this.personRole.contains(newPersonRole)) {
			this.personRole.add(newPersonRole);
			newPersonRole.setRole(this);
		} else {
			for (PersonRoleFace temp : this.personRole) {
				if (newPersonRole.equals(temp)) {
					if (temp != newPersonRole) {
						removePersonRole(temp);
						this.personRole.add(newPersonRole);
						newPersonRole.setRole(this);
					}
					break;
				}
			}
		}
	}

	public void removePersonRole(PersonRoleFace oldPersonRole) {
		if (oldPersonRole == null)
			return;
		if (this.personRole != null)
			if (this.personRole.contains(oldPersonRole)) {
				for (PersonRoleFace temp : this.personRole) {
					if (oldPersonRole.equals(temp)) {
						if (temp != oldPersonRole) {
							temp.setRole((Role) null);
						}
						break;
					}
				}
				this.personRole.remove(oldPersonRole);
				oldPersonRole.setRole((Role) null);
			}
	}

	public void removeAllPersonRole() {
		if (personRole != null) {
			PersonRoleFace oldPersonRole;
			for (java.util.Iterator<PersonRoleFace> iter = getIteratorPersonRole(); iter.hasNext();) {
				oldPersonRole = (PersonRoleFace) iter.next();
				iter.remove();
				oldPersonRole.setRole((Role) null);
			}
			personRole.clear();
		}
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public java.lang.String getDescription() {
		return description;
	}

	public void setDescription(java.lang.String description) {
		this.description = description;
	}
}

The code in packageB is as follows:


package myPackageB;

public interface PersonRoleFace {

	void setPerson(Person person);

}
package myPackageB;

import myPackageA.Role;

public class PersonRole extends PojoSupport<PersonRole>
		implements myPackageA.PersonRoleFace, myPackageB.PersonRoleFace {

	private Integer id;

	private Person person;

	private Role role;

	public Person getPerson() {
		return person;
	}

	public void setPerson(Person newPerson) {
		if (this.person == null || this.person != newPerson) {
			if (this.person != null) {
				Person oldPerson = this.person;
				this.person = null;
				oldPerson.removePersonRole(this);
			}
			if (newPerson != null) {
				this.person = newPerson;
				this.person.addPersonRole(this);
			}
		}
	}

	public Role getRole() {
		return role;
	}

	public void setRole(Role newRole) {
		if (this.role == null || this.role != newRole) {
			if (this.role != null) {
				Role oldRole = this.role;
				this.role = null;
				oldRole.removePersonRole(this);
			}
			if (newRole != null) {
				this.role = newRole;
				this.role.addPersonRole(this);
			}
		}
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}
}
package myPackageB;

public class Person extends PojoSupport<Person> {
	private Integer id;
	private java.lang.String name;
	private java.util.Collection<PersonRoleFace> personRole;

	public java.util.Collection<? extends PersonRoleFace> getPersonRole() {
		if (personRole == null)
			personRole = new java.util.LinkedHashSet<PersonRoleFace>();
		return personRole;
	}

	public java.util.Iterator<? extends PersonRoleFace> getIteratorPersonRole() {
		if (personRole == null)
			personRole = new java.util.LinkedHashSet<PersonRoleFace>();
		return personRole.iterator();
	}

	public void setPersonRole(java.util.Collection<? extends PersonRoleFace> newPersonRole) {
		removeAllPersonRole();
		for (java.util.Iterator<? extends PersonRoleFace> iter = newPersonRole.iterator(); iter.hasNext();)
			addPersonRole((PersonRoleFace) iter.next());
	}

	public void addPersonRole(PersonRoleFace newPersonRole) {
		if (newPersonRole == null)
			return;
		if (this.personRole == null)
			this.personRole = new java.util.LinkedHashSet<PersonRoleFace>();
		if (!this.personRole.contains(newPersonRole)) {
			this.personRole.add(newPersonRole);
			newPersonRole.setPerson(this);
		} else {
			for (PersonRoleFace temp : this.personRole) {
				if (newPersonRole.equals(temp)) {
					if (temp != newPersonRole) {
						removePersonRole(temp);
						this.personRole.add(newPersonRole);
						newPersonRole.setPerson(this);
					}
					break;
				}
			}
		}
	}

	public void removePersonRole(PersonRoleFace oldPersonRole) {
		if (oldPersonRole == null)
			return;
		if (this.personRole != null)
			if (this.personRole.contains(oldPersonRole)) {
				for (PersonRoleFace temp : this.personRole) {
					if (oldPersonRole.equals(temp)) {
						if (temp != oldPersonRole) {
							temp.setPerson((Person) null);
						}
						break;
					}
				}
				this.personRole.remove(oldPersonRole);
				oldPersonRole.setPerson((Person) null);
			}
	}

	public void removeAllPersonRole() {
		if (personRole != null) {
			PersonRoleFace oldPersonRole;
			for (java.util.Iterator<? extends PersonRoleFace> iter = getIteratorPersonRole(); iter.hasNext();) {
				oldPersonRole = (PersonRoleFace) iter.next();
				iter.remove();
				oldPersonRole.setPerson((Person) null);
			}
			personRole.clear();
		}
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public java.lang.String getName() {
		return name;
	}

	public void setName(java.lang.String name) {
		this.name = name;
	}
}

(There are PojoSupport classes in both packageA and packageB, which are exactly the same as before, and will not be repeated here)

​ Now we can put the myPackageA package in Maven module A, and put the myPackageB package in Maven module B. PersonRole needs to implement the myPackageA.PersonRoleFace interface, so B depends on A, which realizes the project using bidirectional correlation model modeling at the same time. Has the advantage of Maven's ease of extensibility.

Summarize

       The code in this article can be found at  https://gitee.com/limeng32/biDirectPojo  . The bidirectional correlation model is a new theory discovered during the development of object-oriented programming, which represents a deeper understanding of the nature of model relationships for software developers. We all have the experience that advanced software must be based on advanced algorithms, and the idea of ​​modeling is also an algorithm. Of course, the road of algorithm exploration is never-ending, but at present in the software field of B/S architecture, the bidirectional correlation model does have excellent performance, and we can safely use this modeling method as our increasingly complex network application. cornerstone.

Easter eggs

      This article is one of the theoretical foundations that my open source project flying (see  https://www.oschina.net/p/flying for the address ) needs to use when developing the latest version. Because this new version of flying has added a lot of innovation, it is expected that there will be another theoretical article describing the new features soon. By the way, because flying has to release multiple versions each time to adapt to different versions of mybatis, the next version will no longer use the numerical name, but replaced by the Chinese character "first snow", probably when Beijing ushered in the first snow. can be published. As for why it is such a poetic name, let me sell it here, you will understand when you see the new feature of flying-first snow.

{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324157823&siteId=291194637