/darks-orm

A simple database ORM framework.

Primary LanguageJavaApache License 2.0Apache-2.0

Darks ORM

Darks is a comprehensive type of lightweight ORM data persistence layer framework, integrated Hibernate "automation" ORM framework for the convenience, stability, as well as the Mybatis ORM framework "semi-automatic" efficient, high concurrency, set two ORM patterns as a whole.The framework to simplify the cumbersome configuration process, using Jython script language extensions, as a dynamic SQL language realization scheme.Construction of a highly efficient multi function domain data cache, and integrated EhCache third party data cache.

Feature 1.0.3

  • Support Javascript sqlmap aspect script.
  • Support if,elseif,else,where,set,trim,foreach nested tags for sqlmap DML.
  • Support logic expression for condition tags.
  • Remove custom logger.
  • Support ORM spring configuration scanner.
  • Change XSD to DTD validate.
  • Fixed some query method bugs.

Feature 1.0.1

  • Support SQL language query, the result set for the JAVA object automatic mapping.
  • Support chain data source configuration.When the main data source connection access failure, will automatically switch to the associated data source access node.
  • Support annotation data entity class form of annotation, annotation support a one-to-one, one-to-many, many-to-one relationship mapping model, support query annotations lazy.
  • Support lazy loading, whole frame using lazy loading mechanism.
  • Support the use of SQL statements for a single entity, the entity list query, query paging query, query entity list various cascades.In a concatenated query, framework will automatically find the result set save In the associated entity data, if there will be automatically cascaded mapping, effective use of the result set data.
  • Support for normal JDBC services.
  • Support for multiple data source configuration. Framework default integration of BoneCP data connection pool framework. In addition, able to use JDBC, BoneCp, JNDI, custom and so on many kinds of data source type.
  • Support with the Spring framework integration.
  • Support general (non object relational mapping) JDBC query and update method.
  • Support the SQL and source code separation to XML mapping configuration, i.e. using SqlMap mode of mapping the query update.
  • SqlMap support normal query, cascade query, select query, combination query, dynamic SQL query and other enquiries.
  • SqlMap dynamic SQL query support Jython script (Python JAVA), JavaBean, custom and other scripting language of the dynamic blocking modification.
  • Support SqlMap with JAVA interface and the JAVA abstract class mapping.The JAVA abstract class mapping in SqlMap mapping, join TemplateDAO encapsulation method for calling.
  • Support the integration of EhCache data cache, data cache framework.Can choose to use the framework itself cache mechanism or the third cache mechanism.The caching mechanism includes application level cache, thread cache level as well as the session level cache (WEB application support).

Get Package

You can get latest jar package from darks-orm/release.

Configuration

You should create configuration file "darks.xml" under root source directory.

<dataSource> Tag

dataSource tag is used to configure database source information. It also can be built chain structure, which can use next dataSource node when current node's connection is invalid or occur error.
Examples:

<dataSource type="jdbc" id="jdbc" main="true">
	<property name="driver" value="com.mysql.jdbc.Driver"></property>
	<property name="url" value="xxxxxx"/>
	<property name="username" value="xxxxxx"/>
	<property name="password" value="xxxxxx"/>
	<property name="fetchSize" value="0"></property>
	<property name="autoCommit" value="true"></property>
	<resultSet type="scroll" sensitive="false" concurrency="read"></resultSet>
</dataSource>

<dataSource type="bonecp" id="bonecp" chainref="jdbc">
	<property name="driver" value="com.mysql.jdbc.Driver"></property>
	<property name="url" value="xxxxxx"></property>
	<property name="username" value="xxxxxx"></property>
	<property name="password" value="xxxxxx"></property>
	......
	<resultSet type="scroll" sensitive="false" concurrency="read"></resultSet>
</dataSource>

<dataSource type="jndi" id="jndi" chainref="bonecp">
	<property name="fetchSize" value="0"></property>
	<property name="autoCommit" value="true"></property>
	<property name="jndiPoolName" value="java:comp/env/jdbc/xxxxxx"></property>
	<resultSet type="scroll" sensitive="false" concurrency="read"></resultSet>
</dataSource>

The above example indicate that if JDBC fail to get connection, bonecp connection will try again. And if bonecp failed, jndi will try again.

<entities> Tag

If you want to load entities when startup or use entity's alias for sqlmap, you should use entities to define which class will be loaded when startup. You even can use child tag to define all classes under target package.
Examples:

<entities>
	<entity alias="User" class="darks.orm.test.model.User"/>
	<entity alias="Depart" class="darks.orm.test.model.Depart"/>
	....
	<package name="darks.orm.test.model"/>
</entities>

<cacheGroup> Tag

cacheGroup tag is used to configure global or local cache configuration. Cache can act on all executing method as global cache, it also can act on specify method as local cache.
Cache has some action scope. will live on the application scope, will just live on the current thread scope, will call EhCache to manage cache objects.
Examples:

<cacheGroup use="true" type="auto" cacheId="application" synchronous="true">
	<appCache strategy="Lru" 
			  ....
			  copyStrategy="serial"/>
	<threadCache  strategy="Lru" 
				  ....
				  entirety="true"
				  copyStrategy="serial"/>
	<ehCache id="ehcache1"
			 maxElementsInMemory="10000"
			 eternal="false"
			 ....
             memoryStoreEvictionPolicy="LRU"/>
</cacheGroup>

<sqlMapGroup> Tag

sqlMapGroup tag is used to configure sqlmap configuration files paths.
Examples:

<sqlMapGroup>
	<sqlMap>/sqlmap-*.xml</sqlMap>
</sqlMapGroup>

Spring Configuration

If you have configured datasource both darks.xml and springContext.xml, the spring's datasource will be the main datasource, and other datasource configured in darks.xml will be its child node.
Examples:

<bean id="testDataSource" class="org.apache.commons.dbcp.BasicDataSource">
	<property name="driverClassName" value="com.mysql.jdbc.Driver" />
	<property name="url" value="xxxxxx" />
	<property name="username" value="xxxxx" />
	<property name="password" value="xxxxx" />
</bean>

<bean class="darks.orm.spring.SqlSessionFactoryBean">
	<property name="dataSource" ref="testDataSource" />
	<property name="scanPackages" value="darks.orm.test.mapper,darks.orm.examples.mapper" />
	<property name="configLocation" value="classpath:darks.xml" />
	<property name="dataParamConfig.autoCommit" value="true" />
	<property name="dataParamConfig.resultSetType" value="scroll" />
	<property name="dataParamConfig.sensitive" value="false" />
	<property name="dataParamConfig.concurrency" value="read" />
</bean>

Define Entity

@Entity("users")
public class User
{
	//@Id(feedBackKey = FeedBackKeyType.SELECT, select = "SELECT LAST_INSERT_ID()")
    //@Id(type = GenerateKeyType.SELECT, select = "SELECT LAST_INSERT_ID()")
    @Id
    @Column("id")
    private int userId;
    
    @Column("name")
    private String userName;
    
    @Column(value="pwd", nullable=false)
    private String userPwd;
    
    @Column("depart_id")
    private Depart depart;
    
    @Column("type")
    private Integer type;
    ....
    
    //@OneToOne(resultType = Depart.class, SQL = "select * from t_depart where depart_id = ?")
    @OneToOne(resultType = Depart.class, mappedBy = "departId", mappedType = MappedType.EntityType)
    public Depart getDepart()
    {
        return depart;
    }
    
    //@ManyToOne(classType=Depart.class, SQL="select * from t_depart where depart_id = ?")
    //@ManyToOne(resultType = Depart.class, mappedBy = "departId", mappedType = MappedType.EntityType)
    
    @OneToMany(resultType = User.class, mappedBy = "depart", mappedType = MappedType.EntityType)
    public List getUsers(){...}
    ....
    
    @Query(SQL="select * from users where parent_id = ?", 
			resultType=User.class, queryType=QueryType.SingleType, paramType={"id"})
	public List getUsers()
	{
		return null;
	}
}

Basic Call

You can call executeQuery or executeUpdate to execute original JDBC method directly. And you can call queryList, queryById, queryPageList etc to execute ORM method. queryCascadeXXX can query entities object by cascade way.
Examples:

List users = session.queryList(User.class, "select * from users where name = ?", "darks");
Page page = session.queryPageList(User.class, "select * from users", page, pageSize);
session.save(new User(....));
session.update(user);
session.delete(User.class, userId);
session.delete(user);
session.executeQuery(....);

SqlMap Call

Build Mapper

public interface UserMapper
{

	public List queryUsers(@Param("type")int type);

	public List queryUsersByIds(@Param("ids")List ids);
	
	public Page queryUsersPage(@Param("cur")int page, int pageSize);
	
	public void updateUser(@Param("id") Integer id, @Param("name")String name);
	
	public void updateUserEntity(@Param("user")User user);

	public List queryUsersComplex(@Param("user")User user);

	public List queryUsersAspect(@Param("user")User user);
	
}

You can also use abstract class. And if you extends class 'TemplateDAO', the class can both calling basic methods and mapper methods.

public abstract class UserMapper extends TemplateDAO
{

	public abstract List queryUsers(@Param("type")int type);
	...
	public abstract List queryUsersAspect(@Param("user")User user);
	...
}

Call Mapper

API Way

SqlSession session = SqlSessionFactory.getSession();
UserMapper userMapper = session.getSqlMap(UserMapper.class);
...

Spring Way

@Resource
UserMapper userMapper;
...

Sqlmap File

DML/DDL

You can use DML tag to configure method mapping or use DDL tag to create,alter tables etc. The methods configured in DDL tag will be called when application startup.

  



	<DML namespace="darks.orm.test.mapper.UserMapper">
		....
	</DML>
	<DDL>
		....
	</DDL>

Sqlmap Tags

You can use tag <where>, <trim>, <foreach>, <if>, <set> etc to modify your SQL dynamically.

<tag id="fieldsUser">
id,name,pwd,depart_id
</tag>

<Query id="queryUsersComplex" queryType="list" resultType="monitor">
	select 
	<include refid="fieldsUser"/>
	from users 
	<where>
		<if test ="user.type != null">
			<if test="user.type == 1">
				type=#user.type
			</if>
			<elseif test="user.type == 2">
				type=#user.type
			</elseif>
			<else>
				type=#user.type
			</else>
		</if>
	</where>
	limit 10
</Query>

<Update id="updateUserEntity">
	update users 
	<set>
		<if test="user.name != null">
			name = #user.name,
		</if>
		<if test="user.pwd != null">
			pwd = #user.pwd,
		</if>
		<if test="#1.type > 0">
			type = #user.type,
		</if>
	</set>
	where id=#user.id
</Update>

Sqlmap Aspect

You can use python, javascript, java as the aspect script to do something before SQL executed and after SQL executed.

Python/Jython

<Query id="queryUsersComplex" queryType="list" resultType="monitor">
	select 
	<include refid="fieldsUser"/>
	from users 
	<where>
		<if test ="user.type != null">
			<if test="user.type == 1">
				type=#user.type
			</if>
			<elseif test="user.type == 2">
				type=#user.type
			</elseif>
			<else>
				type=#user.type
			</else>
		</if>
	</where>
	limit 10
	<aspect>
		<jython className="TestAspect">
			class TestAspect(IAspect):
				def before(self):
					print __DATA.sql
					for _user in __DATA.methodParams:
						print _user
					__DATA.sql = "select * from users limit 5"
					return 1
		</jython>
	</aspect>
</Query>

Javascript

<Query id="queryUsersComplex" queryType="list" resultType="monitor">
	select 
	<include refid="fieldsUser"/>
	from users 
	<where>
		<if test ="user.type != null">
			<if test="user.type == 1">
				type=#user.type
			</if>
			<elseif test="user.type == 2">
				type=#user.type
			</elseif>
			<else>
				type=#user.type
			</else>
		</if>
	</where>
	limit 10
	<aspect>
		<javascript>
			function before(wrapper)
			{
				var user = wrapper.methodParams[0];
				if (user.type == 2)
				{
					wrapper.sql = "select * from users limit 5";
				}
				return true;
			}
		</javascript>
	</aspect>
</Query>

I wish you a pleasant to use darks-orm. If you have some good advice or bug report, please share with us. Thank you!