Migrating a batch of old code to nuggets this part of the tool is no longer maintained, can exchange learning, but unable to maintain improvements

The old code

This is from a very long time ago. I didn’t have the habit of git or blog before, but now I throw it up as a memento. many things in it are not useful anymore, especially now that it is more and more popular, convenient, and efficient

Disassemble learning complex large wheels

Before the study analysis of daishen full set of framework source code after learning output

BeeFramework

Guo Dasen’s super famous set of APP development framework, covering the content is very rich, very comprehensive, here is not introduced, every module and every detail is like a treasure house there are more things worth learning

At the beginning, I wanted to focus on the database-related content, so I focused on dismantling the DB module of the BeeFramework. Since there is a set of signal information flow system unique to Bee between each sub-module of Bee, and the idea of data flow runs through every corner of the whole framework from top to bottom, so his database module is very exquisite. But there’s a big price to pay for taking it out and using it alone.

Therefore, the database sub-module of Bee was independent, stripped and sorted out. From the perspective of learning, THE ORM code of learning Bee was disassembled, the MRC was removed and ARC was changed (Bee was still MRC when LEARNING at the beginning), the SQL tool of learning Bee was disassembled, and some more flexible interface control was added from the peripheral interface design. And slightly extended the orM case for table correlation

Thank you so much for daishen’s open source project

Database AIDS

For FMDB, write a set of ORM and SQL AIDS

  • Automatic ORM that converts the dictionary returned by FMDB into objects
  • Automatic SQL generation and processing, support chain syntax without learning SQL, generate SQL statements
  • Support developers to write complex SQL syntax directly and flexibly

Directions for use

Introduction of the DataBase

This is a database framework based on FMDB, FMDB in the use of multiple database management, synchronous, asynchronous database, thread safety, but FMDB in the working principle, the input parameters must be SQL statements, which has high requirements on the user’s database related knowledge.

In the use of FMDB, SQL statement strings must be passed error-free to FMDB to return dictionary query results.

It is packaged on top of FMDB, uses powerful Objective-C runtime control, and can dynamically generate create, Query, INSERT, update statements and execute them on any business model without requiring iOS developers to know anything about databases. And the dictionary table data returned by FMDB can be dynamically and automatically resolved as any business model object, without any development action

It is composed of a powerful dynamic runtime adaptation module and SQL statement generation module

Dynamic runtime adapter module: any custom business model through the runtime into a dictionary table data, and can check out by db dictionary table data reverse transformation back any custom business model, the framework of this process with the aid of VKFMDBHelper pure completion, iOS developers on this, do not need to undertake any additional development

SQL statement generation module: through the automatic conversion of dictionary table data, automatic generation of CREATE, Query, INSERT, update and other SQL code, iOS developers can completely do not understand the database, but also can complete database operations. If the developer is proficient in SQL, it also supports writing complex and efficient SQL statements by itself, which can be executed directly and is more flexible

DataBase Third-party dependencies

  • FMDB third-party SQLite database
  • MacOS 10.7 and later
  • Xcode 4.6 or later

Environment configuration

  • Import FMDB into the project, either way
    • cocoapod pod 'FMDB'
    • Source import
  • Refer directly to the header fileVKDBManager.hYou can use DBManager
  • Custom objects inherit directly fromVKDBModelCan automatically enjoy dynamic matching, automatic SQL generation function

Basic usage

1 Create a custom data object

Create an object model for database management that inherits from VKDBModel. For example, create a class named Person that has firstName, lastName, Age, and personId.


@interface person : VKDBModel

@property (nonatomic.strong) NSString* personId;

@property (nonatomic.strong) NSString* firstName;

@property (nonatomic.strong) NSString* lastName;

@property (nonatomic.assign) NSInteger age;

@end
Copy the code

This simple Person class automatically has the ability to dynamically match table data at runtime, automatically generate SQL, and so on

How to use the following details

2 About primary keys

VKDBModel automatically creates an implied auto-increment primary key property named dataBaseId

If the user does not specify a primary key, the database framework will still work

The uniqueKeyName method needs to be overridden in the Person class to specify personId as the user’s primary key

+ (NSString *)uniqueKeyName
{
	return @"personId";
}
Copy the code

3 Opening the Database

If the openDefault method is used, it will automatically create and open the database with app Bundlename as the database name

[[VKDBManager defaultManager] openDefault]
Copy the code

VKDBManager itself is a singleton. It can open and close multiple databases at the same time and switch the database in use. For details, see the related interface documentation

4. Data model mapping and table building

Each VKDBModel model needs to be mapped before it is used, and the mapping table of attributes can be established at runtime before it can be converted at runtime and automatically generated by SQL

Each VKDBModel model must first create a successful table in the database, if the table has been built to repeat the call is ok

[K12StudyKeyPointDBModel buildTable];SQL > create table or mark table
Copy the code

5 Writing data to the Database

Create a Person object, assign it a value, and execute saveToDB

Automatically generate the SQL statements needed to write the Person object to the database

Automatically execute this SQL statement in an open database

Finally, the process of entering the Person object into the library is implemented

person* p = [[person alloc]init];
p.personId = @ "1";
p.firstName = @"defu";
p.lastName = @"wang";
p.age = 28;

[p saveToDB];

Copy the code

6 Refresh data from the database

If a Person object already has a value for the user’s primary key, calling the refresh method automatically reads the data under that primary key from the database and assigns the value to person

Automatically generate the primary key-value read SQL statement for the Person object

Automatically assigns a run-time match to person from a table structure read from the database

person* p = [[person alloc]init];
p.personId = @ "1";

[p refresh];
    
Copy the code

7 Query information in the database

Gets all objects under the Person table, or a collection of objects in a range under the Person table

SQL statements that automatically generate query

Fetch a large amount of table data from the database

One-click automatic mapping to objects

NSArray* result1 = [person allObjectData]; NSArray* result2 = [person objectDataWhereKeyName:@"lastName" Opertor:@"=" Value:@"wang"]; NSArray* result3 = [Person objectDataWhereKeyName:@"age" Opertor:@"<" Value:@"50"]; NSMutableArray* objectArr = [[NSMutableArray alloc]init]; for (NSDictionary* itemdic in result1) { person* p = [[person alloc]initWithDictionary:itemdic]; [objectArr addObject:p]; }Copy the code

Flexible usage

1 Core Ideas

  • With VK_SqlGenerator, YOU can generate SQL statements based on behavior and semantics without knowing SQL syntax

  • Each operation can generate a STRING of SQL statements to be executed by the VKDBManager

  • Each lookup of the database returns a dictionary, not an object

  • Dictionaries can be converted to objects with one click, using run-time matching

  • SaveToDB refresh is internally packaged, executed, and converted into an object assignment

2 Flexibly generate Sql statements

VK_SqlGenerator adopts the popular chain syntax, and generates SQL statements smoothly under the semantic expression

  • .table.From is the start of a generator, and From is used more often.Table is used to create tables, and is wrapped in the buildTable method

  • Set and so on are in the middle of the generator, used to perform filtering, or Set fields, and these statements can be repeated, Set multiple times, or filter multiple conditions

  • Get.update.insert.Create, etc., are the end of the generator and execute this method, which will eventually generate the final SQL statement based on the path previously executed and return

Example for generating database SQL statements

NSString* getSql = VK_SqlGenerator.FROM([person tableName]).WHERE_OPERATOR(@"age".@ "<".28 "@").WHERE_OPERATOR(@"lastName".@ "=".@"wang").GET();
Copy the code

This is a lookup of two combined filters

NSString* sql = VK_SqlGenerator.FROM(self.tableName).WHERE_OPERATOR(@"course".@ "=",course).DELETE();
 	
Copy the code

This is the deletion of a single filter

VK_SqlGenerator .FROM( [person tableName] ) .WHERE( @"personId", @"1" ); For (attribute run mapping loop) {vk_SQLGenerator.set (name, value); } NSString* updateSql = VK_SqlGenerator.UPDATE();Copy the code

This is a data update loop with a filter and the assignment part is pseudocode, wrapped in saveToDB

3 Execute handwritten SQL statements

If the developer has database knowledge and ability, can write their own complex SQL statements, directly to VKDBManager to execute

Especially database upgrade alternate and other complex operations

Has not done a good job of database migration upgrade powerful statement generator

NSString* updateSql = @"INSERT INTO tablename SET column_name1 = value1, column_name2 = value2";
/ / write SQL
[VKDBManager doUpdateSQL:sql];
// Execute doUpdate if a write statement is written
[VKDBManager doQuerySql:sql];
// Execute doQuery if you are writing a query
    
Copy the code

4 Query table data for mapping to objects

Because the data returned by the query interface is a dictionary structure, not an object, a conversion is required

person* p = [[person alloc]initWithDictionary:itemdic];// Automatically convert arrays to objects with one click
Copy the code

5 Flexible use

SQL generation, execution, and dictionary mapping are the core of VKommonX DataBase, which can be flexibly disassembled, changed, and used to achieve variable expansion

Asynchronous operations

1 Asynchronous Mode

  • FMDB supports passing in a set of SQL statements, completing by its internal asynchronous queue, and finally calling back the results via a block

  • VKFMDBHelper encapsulates this and all SQL statements can be executed directly or passed into Mannager’s SQL queue manager for a unified asynchronous execution

  • To handle asynchronous callbacks, VKFMDBHelper encapsulates an event registration mechanism so that each asynchronous operation can be listened for in the main thread after it is registered

2 Asynchronous Database Operation Flow

  • Register asynchronous database listening events, all asynchronous data returned by listening events, in order to distinguish different events, each event in the submission of the time can specify a tag, according to the different tag to different processing returned data

    [[VKDBManager defaultManageVKr]addDataBaseNotificationAtTarget:self withComplete:^(NSString *tag, BOOL succuse, NSArray *result) {

    If ([tag isEqualToString:@”event”]) {// NSLog(@” CCCCC “); }}];

  • Start asynchronous operations, including asynchronous search and asynchronous write

    [VKDBManager beginBackgroundUpdate]; [VKDBManager beginBackgroundQuery];

  • Write SQL statements to asynchronous queues

    • You can add directly to the queue by generating SQL statements
    • It can also be automatically added to the queue by encapsulation of a single object saveInBackground deleteInBackground and other VKDBModel methods, but it is not executed for the time being

// Put the generated SQL into the corresponding queue
[VKDBManager addUpdateTaskSQL:sql];
[VKDBManager addQueryTaskSQL:sql];

// Queue with VKDBModel encapsulation method
person* p;
[p saveInBackground];
[p deleteInBackground];
// Add the automatically generated SQL to the UPDATE queue
Copy the code
  • withVKDBManagerTo submit an unexecuted SQL statement in the SQL queue, you can submit it with a tag name, or use the default tag if you do not have onedefaultUpdate or defaultQuery
[VKDBManager commitBackgroundUpdateWithTaskTag:@"savetask"];// Submit the tag as savetask
[VKDBManager commitBackgroundUpdate];// Submit the tag as the default tag
	 
Copy the code
  • The data is returned as an array, which is a dictionary structure that needs to be manually converted to an object by one key

SQL queue manager

VKSQLQueueManager SQL queue manager contains two queues, update “” query two queues, which are unrelated to each other,

  • Each BEGIN operation clears the queue
  • Each COMIT operation also empties the queue

4 Using an Example

[[VKDBManager defaultManager]addDataBaseNotificationAtTarget:self withComplete:^(NSString *tag, BOOL succuse, NSArray *result) { if ([tag isEqualToString:@"savetask"]) { } }]; [VKDBManager beginBackgroundUpdate]; NSLog(@"aaa time ==="); for (NSInteger i = 300; i < 4000; i++) { K12KeyPointVisitDBModel * model = [[K12KeyPointVisitDBModel alloc]init]; model.kpid = [NSString stringWithFormat:@"adfadf%@",@(i)]; model.deltaCount = 100; [model saveInBackground]; / / loop will SQL string is added to the queue} [VKDBManager commitBackgroundUpdateWithTaskTag: @ "savetask"].Copy the code

Data inline

1 aVKDBModelContains another oneVKDBModel

Create a new VKDBModel object for Dog

	
@interface dog : VKDBModel

@property (nonatomic.strong)NSString* dogId;

@property (nonatomic.strong) NSString* dogName;

@end

Copy the code

Rewriting the Person object


@interface person : VKDBModel

@property (nonatomic.strong)NSString* personId;

@property (nonatomic.strong) NSString* firstName;

@property (nonatomic.strong) NSString* lastName;

@property (nonatomic.assign) NSInteger age;

@property (nonatomic.strong) dog* pet;

@end	
Copy the code
  • When creating a table on person, the dog field is treated as a string and the uniqueKey of the dog class is stored in the database (dog must override the uniqueKey, otherwise an assertion error is reported).

  • When the Person object is saved, a DOG SQL is generated and executed from the PET property of The Person, and a Person SQL is generated and executed

  • When saveInBackground is applied to the Person object, two SQL statements are directly generated and entered into the SQL queue

  • The dog property of Person, whether read by refresh or dictionary conversion, is null except for uniqueKey

  • Only uniqueKey has a value for the dog property. RefreshInnerDBModel is performed on the other empty Person to complete the dog object

// The dictionary results found in person's table are converted to objects
person* p = [[person alloc]initWithDictionary:itemdic];
// The result of the person directly refresh
person *p =[[person alloc]init];
p.personId = @ "1";
[p refresh];

// The dog attribute object of the above two results p, only dogId has the value, and other attributes of dog such as dogname are empty
[p refreshInnerDBModel];
// complete the dog attribute of p
    
Copy the code

2 aVKDBModelContains an array of other arraysVKDBModel

Rewriting the Person object


@interface person : VKDBModel

@property (nonatomic.strong)NSString* personId;

@property (nonatomic.strong) NSString* firstName;

@property (nonatomic.strong) NSString* lastName;

@property (nonatomic.assign) NSInteger age;

@property (nonatomic.strong) NSArray* pets;

@end	

Copy the code
  • When creating a table on Person, the PETS field is treated as a string

  • Serialize the unique keys of all dog objects in the PETS array into strings and store them in the database (dog must override the uniqueKey, otherwise an assertion error will be reported)

  • When the Person object is saved, the PETS property of the Person is used to generate a set of DOG SQL and execute it, as well as a Person SQL and execute it

  • When saveInBackground is applied to the Person object, N+1 SQL statements are generated directly into the SQL queue

  • When reading data, either through refresh or dictionary conversion, only the uniqueKey has a value for the dog object in the PET array. The rest is null

  • The value of the dog object can be completed by performing refreshInnerDBModel on person

// The dictionary results found in person's table are converted to objects
person* p = [[person alloc]initWithDictionary:itemdic];
// The result of the person directly refresh
person *p =[[person alloc]init];
p.personId = @ "1";
[p refresh];

// The dog attribute object of the above two results p, only dogId has the value, and other attributes of dog such as dogname are empty
[p refreshInnerDBModel];
// complete all object attributes of the dog array of p
Copy the code

3 Data inline description

VKFMDBHelper database module does not support very powerful data inlining between objects, association lookup function, only the most basic form of inlining.

You can start with the business database table structure and simplify the table structure correlation to use VKFMDBHelperVK’s database

If the service needs a more advanced data inline mode, or the existing functions cannot meet the requirements, you can choose the method of handwritten SQL statements and self-assignment of business logic to complete more complex functions

VKFMDBHelperVK data inline, may not be stable, will be updated continuously

Matters needing attention

  • VKDBModel supports only NSNumber(NSInterge CGFloat) NSDate NSArray NSString

  • NSArray only has NSString, NSNumber

  • An error is asserted if an unsupported property field is present

  • An inline object without a uniqueKey is asserting an error

  • An error is reported when an NSDictionary is present in an attribute (not supported, but can be extended later, only NSString and NSNumber are valid within the dictionary)

  • The interface for all asynchronous operations must be called from the main thread, which will assert an error because internal thread management is unified

The interface,

1 VKDBModel

-(instancetype)initWithDictionary:(NSDictionary*)dic;

Dictionaries are automatically converted to VKDBModel objects

+(NSString*)uniqueKeyName;

Overload, specifying a unique uniqueKey

+(BOOL)buildTable;

Build table, main thread, repeatable execution

+(BOOL)clearTable;

Clear the table, main thread

-(BOOL)exsit;

Object’s uniqueKey exists in the database

-(BOOL)refresh;

Use the uniqueKey of the object, look it up in the database, and assign it to the object

-(void)refreshInnerDBModel;

Completes other properties of the inline object

-(void)saveInBackground;

Generate save SQLString, put into queue

-(void)saveToDB;

Generate save SQLString, execute directly

-(void)deleteFromDB;

Generate delete SQL, execute directly

-(void)deleteInBackground;

Generate delete SQL and queue it

+(NSArray*)allObjectData;

Generate search all SQL, directly executed

+(void)allObjectDataQuerryInBackground;

Generate find all SQL, put into the queue

+(NSArray*)objectDataWhereKeyName:(NSString*)key Opertor:(NSString*)opera Value:(NSString*)value;

Generate conditional lookup SQL, executed directly

+(void)objectDataQuerryInBackgroundWhereKeyName:(NSString*)key Opertor:(NSString*)opera Value:(NSString*)value;

Generate conditional lookup SQL and queue it

2 VKDBManager

- (instancetype)sharedInstance;

+ (instancetype)defaultManager;

Singleton functions

-(BOOL)openDefault;

Open a database named app bundleID

-(BOOL)closeDefault;

Close the database named app bundleID

-(BOOL)openDataBaseWithName:(NSString*)name;

Open the named database

-(BOOL)closeDataBaseWithName:(NSString*)name;

Close the named database

-(VKDataBase*)currentDataBase;

The database for the current operation

-(void)changeCurrentDataBase:(NSString*)name;

Switch the current database

-(void)changeCurrentDataBaseDefault;

Switch the current operating database to the default database

-(void)addDataBaseNotificationAtTarget:(id)target withComplete:(VKDataBaseQueueBlockReturn)block;

Asynchronous database registration listening, registered with the name of the registered object

-(void)removeDataBaseNotificationAtTarget:(id)target withComplete:(VKDataBaseQueueBlockReturn)block;

The asynchronous database removes the listener and registers with the name of the registered object

-(void)addDataBaseNotificationAtTarget:(id)target withIdentifier:(NSString*)idstr withComplete:(VKDataBaseQueueBlockReturn)block;

Asynchronous database registration listening, registered with a custom name

-(void)removeDataBaseNotificationAtTarget:(id)target withIdentifier:(NSString*)idstr withComplete:(VKDataBaseQueueBlockReturn)block;

Asynchronous database removes listener and registers with custom name

+(NSInteger)lastInsertRowId;

The RowId inserted on the current operating database

+(void)addUpdateTaskSQL:(NSString*)sql;

SQL statement joins write queue

+(void)addQueryTaskSQL:(NSString*)sql;

The SQL statement joins the read queue

+(BOOL)doUpdateSQL:(NSString*)sql;

Execute write statement

+(NSArray*)doQuerySql:(NSString*)sql;

Execute read statement

+(void)beginBackgroundQuery;

Start background lookup and clear the queue

+(void)beginBackgroundUpdate;

Start background write and clear the queue

+(void)commitBackgroundQuery;

If the query fails, the default tag is used

+(void)commitBackgroundQueryWithTaskTag:(NSString*)tag;

Submit query, use tag, failure will not roll by default

+(void)commitBackgroundQueryWithTaskTag:(NSString*)tag errorRollback:(BOOL)enablerollback;

To submit a query, use a tag,

+(void)commitBackgroundUpdate;

Commit write, use default tag, fail not rollback

+(void)commitBackgroundUpdateWithTaskTag:(NSString*)tag;

Commit write, use tag, fail not rollback

+(void)commitBackgroundUpdateWithTaskTag:(NSString*)tag errorRollback:(BOOL)enablerollback;

Commit write, use tag,

3 VKSqlGenerator

  • SQL generator is more flexible to use, various interfaces, not one introduction

  • See the database flexible extension section

  • Chain syntax is used