Llbl Gen 3.x source code tracing and parsing query command Tracing

Source: Internet
Author: User

This section describes how llbl Gen maps entities to SQL statements for database operations.
First, let's look atProgramFragment

[Testmethod]
Public void testfetchsalesorderheader ()
{
Dataaccessadapter adapter = new dataaccessadapter (connectionstring );
Salesorderheaderentity salesorder = new salesorderheaderentity (43659 );
Adapter. fetchentity (salesorder );
Datetime orderdate = salesorder. orderdate;
}

The fetchentity Method for accessing dataaccessadapterbase

Public bool fetchentity (ientity2 entitytofetch)
{
Return fetchentity (entitytofetch, null, entitytofetch. activecontext, null );
}

it has a series of overload methods
Public bool fetchentity (ientity2 entitytofetch, context contexttouse)
Public bool fetchentity (ientity2 entitytofetch, iprefetchpath2 prefetchpath)
Public bool fetchentity (ientity2 partial, incluprefetchpath, context contexttouse)
Public Virtual bool fetchentity (ientity2 entitytofetch, incluprefetchpath, context
contexttouse, please refer)

when reading records, filter is constructed based on the primary key of the object
relationpredicatebucket filter = new relationpredicatebucket ();
ipredicateexpression pkfilter = createprimarykeyfilter (entitytofetch. fields. primarykeyfields);
If (pkfilter = NULL)
{< br> throw new ormqueryconstructionexception ("the entity '" + entitytofetch. llblgenproentityname + "'doesn' t have a PK defined, and fetchentity therefore can't create a query t O fetch it. please define a PK on the entity ");
}< br> filter. predicateexpression. add (pkfilter);
bool fetchresult = fetchentityusingfilter (entitytofetch, prefetchpath, contexttouse, filter, excludedincludedfields);
the parameters of fetchentityusingfilter can be seen, all the usage in the API will eventually become called for this method. Example

1) read all the field values of a database record to the object
Select * from MERs where customerid = 'chops'
Dataaccessadapter adapter = new dataaccessadapter ();

Customerentity customer = new customerentity ("chops ");

Adapter. fetchentity (customer );

2) read only the specified field value, as shown below. Read Only contactname and country

Select contactname, country from MERs where customerid = 'chops'

Customerentity customer = new customerentity ("chops ");

Excludeincludefieldslist excludedfields = new excludeincludefieldslist (false );

Excludedfields. Add (customerfields. contactname );

Excludedfields. Add (customerfields. Country );

Adapter. fetchentitycollection (customers, null, 0, Sorter, null, excludedfields );

3) read database fields other than the specified fields. For example, read all fields except the database Field contactname and country.
Customerentity customer = new customerentity ("chops ");

Excludeincludefieldslist excludedfields = new excludeincludefieldslist (true );

Excludedfields. Add (customerfields. contactname );

Excludedfields. Add (customerfields. Country );

Adapter. fetchentitycollection (customers, null, 0, Sorter, null, excludedfields );

In the original English text

To specify which fields to exclude, you have two options:

    1. Specify the fields to exclude
    2. Specify the fields to fetch (I. e.Include) Which means the rest is excluded.

4) use prefetchpath to read the sub-table of Master/Slave details in the Link record.
The SQL statement is as follows:
Read customer

Select customerid, companyName,... from MERs where country = 'Germany'

Read order
Select orderid, customerid, orderdate,... from orders
Where customerid in
(Select customerid from customers where country = 'Germany ')
Llbl Gen writing
Customercollection MERs = new customercollection ();
Iprefetchpath prefetchpath = new prefetchpath (INT) entitytype. mermerentity );
Prefetchpath. Add (customerentity. prefetchpathorders). subpath. Add (orderentity. prefetchpathorderdetails );
Prefetchpath. Add (customerentity. prefetchpathvisitingaddress );
Ipredicateexpression filter = new predicateexpression ();
Filter. Add (customerfields. Country = "Germany ");
Adapter. fetchentity (filter, prefetchpath );

Method for continuing analysis: bool fetchresult = fetchentityusingfilter (entitytofetch, prefetchpath, contexttouse, filter, excludedincludedfields );
In this method, fields that do not need to be read are processed, and the ing of database fields corresponding to the object is also read.

Ifieldpersistenceinfo [] persistenceinfos = getfieldpersistenceinfos (entitytofetch. fields );
Persistencecore. excludefieldsfrompersistenceinfos (entitytofetch. Fields, persistenceinfos, excludedincludedfields, hierarchytype, discriminatorfieldindex );
Fetchresult = fetchentityusingfilter (entitytofetch. Fields, persistenceinfos, filter)
First, let's look at the implementation of the getfieldpersistenceinfos method.
Protected virtual ifieldpersistenceinfo [] getfieldpersistenceinfos (ientityfields2 fields)
{
Ifieldpersistenceinfo [] persistenceinfo = new fieldpersistenceinfo [fields. Count];
For (INT I = 0; I <fields. Count; I ++)
{
Persistenceinfo [I] = getfieldpersistenceinfo (fields [I]);
}
Return persistenceinfo;
}

Note that the getfieldpersistenceinfo method is used to construct ifieldpersistenceinfo Based on Object Attributes and return

The read method continues and falls into fetchresult = fetchentityusingfilter (entitytofetch. Fields, persistenceinfos, filter );
Its main structure is
Iretrievalquery selectquery = createselectdq (fieldstofetch, persistenceinfos, predicateexpressiontouse, 0, null, filter. relations, true, null, 0, 0 );
Try
{
Onfetchentity (selectquery, fieldstofetch );
Executesinglerowretrievalquery (selectquery, fieldstofetch, persistenceinfos );
Onfetchentitycomplete (selectquery, fieldstofetch );
}
Createselectdq calls dynamicqueryengine to generate iretrievalquery Query
Dynamicqueryenginebase engine = createdynamicqueryengine ();
Return engine. createselectdq (fieldstofetch. getasentityfieldcorearray (),
Persistenceinfoobjects, getactiveconnection (), filter, maxnumberofitemstoreturn, sortclauses, relationstowalk, allowduplicates, groupbyclause, pagenumber, pagesize );

One of the main functions of dataaccessadapter is to bind DQE and dynamic query Enginee.
Protected override dynamicqueryenginebase createdynamicqueryengine ()
{
Return this. postprocessnewdynamicqueryengine (New dynamicqueryengine ());
}
Dynamicqueryenginebase is part of the ORM Support class library and is a basic type. If you want to add SQL server support
Derived from it, override several methods. The relationship between DQE and dynamicqueryenginebase of each database is shown in figure

To some extent, analyze the above stack and draw a conclusion
1) in either database, the databasegeneric part is the same. It is the implementation of the database schema in the program language.
2) databasespecific: binding the implementation of a specific database and the ing between the database schema and. Net object.
Various SQL dialects are slightly different. The purpose of the Assembly SD. llblgen. Pro. DQE. sqlserver. netw.dll is to achieve this difference.

For example, the nuances of the SQL Dialect
A) string connection
MySQL statement, using the Concat Function

Select Concat (ename, 'Works as A', job) as MSG from employee where deptno = 10
SQL Server statement, use +

Select ename + 'Works as a' + job as Meg from employee where deptno = 10
B) Limit the number of returned rows

DB2: Select * from EMP fetch first 5 rows only

MySQL and PostgreSQL: Select * from EMP limit 5

ORACLE: Select * from EMP where rownum <= 5

SQL Server: Select top 5 * from EMP
For more differences in SQL dialects, refer to the "SQL. Cookbook" e-book for details.

Continue to DQE to see how SQL Server generates query statements.

engine. createselectdq (fieldstofetch. getasentityfieldcorearray (),
values, getactiveconnection (), filter, filters, sortclauses, relationstowalk, allowduplicates, groupbyclause, pagenumber, pagesize);

first, let's take a look at the DQE method members. The common select, update, insert, and delete commands are generated by the following methods
During the SELECT statement construction, queryfragments is used to generate SQL statements
queryfragments fragments = new queryfragments ();
fragments. addfragment ("select");
stringplaceholder distinctplaceholder = fragments. addplaceholder ();
stringplaceholder topplaceholder = fragments. addplaceholder ();
delimitedstringlist projection = fragments. addcommafragmentlist (false);
If (relationsspecified)
{< br> fragments. addformatted ("from {0}", relationstowalk. toquerytext ();
query. addparameters (relationcollection) relationstowalk ). customfilterparameters);
}

Appendwhereclause (selectfilter, fragments, query );
Appendgroupbyclause (groupbyclause, fragments, query );
Appendorderbyclause (sortclauses, fragments, query );
Query. setcommandtext (fragments. tostring ());
Finally, convert the constructed queryfragments to a string and pass it to iretrievalquery.
Read this sectionCodeYou can refer to the SELECT statement of the most complete SQL server, including top, distinct, where, group by, and order by to analyze the functions of each method.

Return to the stack's dataaccessadapterbase's fetchentityusingfilter Method


Execute the iretrievalquery query obtained from DQE,
Onfetchentity in dataaccessadapterbase is a virtual method, which is executed before reading data.

Protected virtual void onfetchentity (iretrievalquery selectquery, ientityfields2 fieldstofetch)
{
}

The main body of the executesinglerowretrievalquery method is as follows:
{

Idatareader datasource = NULL;
Try
{
Preparequeryexecution (querytoexecute, true );
Datasource = descrimexecutesinglerowretrievalquery (querytoexecute, commandbehavior. singlerow );
Fetchonerow (datasource, fieldstofill, fieldspersistenceinfo );
}

There is another question that cannot be solved. How does one determine whether the database is SQL server rather than DB2? How does one send SQL statements to the server?
Dataaccessadapterbase also has several fields for database commands

Private string _ transactionname, _ connectionstring;
Private dbconnection _ activeconnection;
Private dbtransaction _ physicaltransaction;
The general dbconnection interface is used here, instead of sqlconnection, oledbconnection, and oracleconnection.
Protected virtual idatareader extends mexecutesinglerowretrievalquery (iretrievalquery querytoexecute, commandbehavior behavior)
{
Return querytoexecute. Execute (behavior );
}
The mmexecutesinglerowretrievalquery method handed over the process to the execute method of the iretrievalquery parameter.
To track the execute method, you need to find the type of the object to which it actually points in the non-Debug state, and return to DQE to generate the iretrievalquery method.
Iretrievalquery toreturn = new retrievalquery (connectiontouse, createcommand ());
Createselectdq (fieldsofselectlist. toarray (), persistenceinfosoffields. toarray (), toreturn, filtertouse, maxnumberofitemstoreturn, sortclauses,
Relationstowalk, allowduplicates, groupbyclause, relationsspecified, sortclausesspecified );
The original type is retrievalquery. Find its execute method. The method content is as follows:
Public dbdatareader execute (commandbehavior behavior)
{
Dbdatareader toreturn = This. Command. executereader (behavior );
That is, execute the command to return the forward cursor variable dbdatareader of express delivery read-only.
The next step is to bind the value in dbdatareader to the attribute of the object.
Enter the method fetchonerow (datasource, fieldstofill, fieldspersistenceinfo );
Private void fetchonerow (idatareader datasource, ientityfields2 rowdestination, ifieldpersistenceinfo [] fieldspersistenceinfo)
{

If (datasource. Read ())
{

Ifieldpersistenceinfo [] persistenceinfosforrowreader = fieldspersistenceinfo;
If (hasexcludedfields)
{
Persistenceinfosforrowreader = fieldutilities. removeexcludedfieldspersistenceinfos (persistenceinfosforrowreader );
}

Readrowintofields (values, rowdestination, fieldnametoordinal, persistenceinfosforrowreader );

Rowdestination. State = entitystate. fetched;
Method readrowintofields: place the value in the attribute and set the state to entitystate. fetched.
Here, there is another type converter application. For example, if the status of the purchase order is "finish" in the database field, "1" indicates that the purchase order has been completed, and "0" indicates that the purchase is in progress (receiving or warehouse acceptance is not completed ).
Salesorderheaderentity salesorder = new sales orderentity (4098 );
Read status bool finish = salesorder. Finish; // 1
Or set salesorder. Finish = true; // 0
Sometimes, Y is used to complete the process, and N is used to represent the Procurement Order in progress. The conversion between true/false and 1/0 of the data record requires type converter.

Conclusion

1. The method for accessing the database in Orm is to use common interfaces such as dbconnection, dbcommand, and dbdatareader. This method has been built into the ORM Support class library, which is different from our method.
Swith (databasetype)

{
Case dbtype. sqlserver:
_ Command = new sqlcommand (text );
Break;
Case dbtype. MySQL:

_ Command = new mysqlcommand (text );

Break;
The only external Type Library DQE related to database dialects is used to construct commands instead of executing commands.

2. the attribute of an object indicates that the fields of ientityfield2 and the database record of the object indicate that ifieldpersistenceinfo is separated, that is, the object does not contain any persistent information. The newly added or deleted object is executed, when modifying a command, the persistenceinfoprovidercore interface is used to construct the field information corresponding to its properties. The iretrievalquery is constructed through some information, and the iretrievalquery is called. executereader reads data.

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.