C # Model Analysis of a lightweight ORM framework (IV)

Source: Internet
Author: User

Concerning the design of the orm framework, it is also necessary to talk about model parsing. It is also an important part, and the implementation is relatively simple.

The main technique used for model Parsing is reflection, that is, ing the attributes of a class to the fields of a table. write out your own design and implementation ideas and hope that some people will give good optimization suggestions. At the same time, they will give new users some inspiration.

First, define features for model attributes. First, popularize the concept of "Features" and why attribute is used ).

Simply put, a feature is to mark a class, method, or attribute (or append information). For more information, see the example,

When ing between classes and tables, we need to know the type, length, primary key, auto-increment, non-null, and other information of a field, the simplest and most intuitive method may be attribute,

First, we define a feature, which is just a class. It must inherit from the attribute. The orm I wrote is lightweight and only a few key attributes are involved,

The Code is as follows:

 
Public class modelattribute: attribute {// <summary> // whether the primary key is used // </Summary> Public bool isprimarykey {set; get ;} /// <summary> /// whether the primary key automatically grows /// </Summary> Public bool isidentity {set; get ;} /// <summary> /// whether the field is not empty /// </Summary> Public bool isnotnull {set; get ;} /// <summary> /// column name /// </Summary> Public String columnname {set; get ;}}
View code

The following is an example of the usage feature of an object class. It specifies that the column name of the ID is "ID". It cannot be empty. It is self-incrementing and is the primary key:

public class Test1 : ModelBase    {        [ModelAttribute(IsPrimaryKey = true, IsIdentity = true, IsNotNull = false, ColumnName = "Id")]        public int Id { set; get; }        public string Name { set; get; }        public string Age { set; get; }        public string Remark { set; get; }    }

The following is a reflection to parse the model feature and paste the core code first:

/// <Summary> /// obtain the parameters of the model object through parsing, key: returns the model parameter for the class property name /// </Summary> /// <Param name = "model"> model object </param> /// <returns> </ returns> protected override dictionary <string, modelattribute> getmodelparam <tModel> () {var list = new dictionary <string, modelattribute> (); propertyinfo [] pros = reflectionhelper. getpropertyinfo <tModel> (); foreach (propertyinfo item in PROs) {var ATTR = reflectionhelper. getcustomattribute <modelattribute> (item); If (ATTR = NULL) {// if the object does not define an attribute, a new ATTR = new modelattribute (); ATTR is created. columnname = item. name;} else {// If the column name is not assigned a value, the column name is defined with the same value as the attribute name if (string. isnullorempty (ATTR. columnname) {ATTR. columnname = item. name ;}} list. add (item. name, ATTR);} return list ;}

Because reflection should be a common method and not limited to model parsing, we proposed reflection-related methods. The following are two methods for obtaining Custom Attributes Based on "type T:

/// <Summary> /// obtain the feature object of the specified member /// </Summary> /// <typeparam name = "T"> type of the attribute to be obtained </ typeparam> // <Param name = "pinfo"> property prototype </param> // <returns> returns the t object </returns> Public static t getcustomattribute <t> (propertyinfo pinfo) where T: attribute, new () {type attributetype = typeof (t); Attribute attrobj = attribute. getcustomattrietype (pinfo, attributetype); t rattrobj = attrobj as t; return rattrobj ;}
View code
/// <Summary> /// obtain all the public attributes of the object // </Summary> /// <typeparam name = "T"> type </typeparam>/ // <Param name = "OBJ"> the obtained object </param> // <returns> returns the Property Information </returns> Public static propertyinfo [] getpropertyinfo <t> () where T: Class {type T = typeof (t); propertyinfo [] proinfo = T. getproperties (); Return proinfo ;}
View code

We don't need to know the specific instance of this class for parsing features, so here we use generic type, just need to know the model type, my framework is limited to class attributes, here, only the "feature object" of the attribute is obtained ".

Return type: dictionary <string, modelattribute> key: attribute name, modelattribute object,

The implementation of parsing is actually completed here, and I have made some optimizations later. We often think of efficiency problems when thinking about reflection, and since it is a feature of parsing a class, so we don't care about its instance object,

Here, the parsed object is put into the cache, that is, only the class is reflected for the first time, and the cached data will be accessed directly in the future.

The Parsing Model is a class, so global cache is required. Here I use a static variable, which cannot be changed externally, so it is set to private.

The Code is as follows:

Static object _ lockobj1 = new object (); static object _ lockobj2 = new object (); // <summary> // entity class cache, static variables are saved to reduce the number of reflections /// </Summary> static dictionary <type, Dictionary <string, modelattribute> _ modelattributecache; /// <summary> // entity class cache. Static variables are saved to reduce the number of reflections. /// </Summary> protected dictionary <type, Dictionary <string, modelattribute> modelattributecache {get {If (_ modelattributecache = NULL) {Lo CK (_ lockobj1) {If (_ modelattributecache = NULL) {_ modelattributecache = new dictionary <type, Dictionary <string, modelattribute> ();}}} return _ modelattributecache; }}/// <summary> // gets the attribute object of the model, after obtaining the data for the first time, it will be put into a cache list. // that is, only reflection is performed once. // </Summary> Public dictionary <string, modelattribute> getmodelattribute <t> () where T: modelbase, new () {type T = typeof (t); If (! Modelattributecache. containskey (t) {lock (_ lockobj2) {If (! Modelattributecache. containskey (t) {var attrs = getmodelparam <t> (); modelattributecache. Add (T, attrs) ;}} return modelattributecache [T];}

The cache list here is: dictionary <type, Dictionary <string, modelattribute>. type is the type of the model class.

Explain the meaning of adding lockobj,

First, let me explain that although this ORM framework is relatively lightweight, I am not sharing the code of a design or test phase. It has also been used in several small projects.

_ Lockobj is a bug found during a multi-threaded operation. When multiple threads access a "global object", access conflict occurs if no lock is applied.

Path of the model parsing class: zhcun. Framework. Common. Models. tablemodel

After downloading the code, you can see detailed implementation methods.

When designing dalbase, we considered that it should rely on the abstract idea. Although we didn't figure out whether there are other methods besides reflection for model parsing, we still defined it as abstract.

 

This completes the model parsing function and will be used when an SQL statement is generated.

With the following method example, it is estimated that the SQL text can be generated.

// Obtain the model object (reflected for the first time and retrieved from the cache when called again) dictionary <string, modelattribute> modelattr = _ modelanaly. getmodelattribute <t> (); // key: field name (attribute name) foreach (string item in modelattr. keys) {// obtain the column name (if the attribute does not specify the columnname value, it is the same as the attribute name) string colname = modelattr [item]. columnname; // whether the word grows. bool isidentity = modelattr [item]. isidentity; // whether the primary key is bool isprimarykey = modelattr [item]. isprimarykey ;}

The implementation of the model parsing class is relatively simple in design.

If you have good suggestions or shortcomings, I hope you can discuss them and correct them.

 

 

Related Article

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.