标签归档:mybatis

Mybatis MapperScannerConfigurer自动扫描

--test--Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring

Mybatis在与Spring集成的时候可以配置 MapperFactoryBean来生成Mapper接口的代理. 例如

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
  <property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
  <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

MapperFactoryBean 创建的代理类实现了 UserMapper 接口,并且注入到应用程序中。 因为代理创建在运行时环境中(Runtime,译者注) ,那么指定的映射器必须是一个接口,而 不是一个具体的实现类。

上面的配置有一个很大的缺点,就是系统有很多的配置文件时 全部需要手动编写,所以上述的方式已经很用了。

没 有必要在 Spring 的 XML 配置文件中注册所有的映射器。相反,你可以使用一个 MapperScannerConfigurer , 它 将 会 查 找 类 路 径 下 的 映 射 器 并 自 动 将 它 们 创 建 成 MapperFactoryBean。

要创建 MapperScannerConfigurer,可以在 Spring 的配置中添加如下代码:

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  <property name="basePackage" value="org.mybatis.spring.sample.mapper" />
</bean>

basePackage 属性是让你为映射器接口文件设置基本的包路径。 你可以使用分号或逗号 作为分隔符设置多于一个的包路径。每个映射器将会在指定的包路径中递归地被搜索到。

注 意 , 没 有 必 要 去 指 定 SqlSessionFactory 或 SqlSessionTemplate , 因 为 MapperScannerConfigurer 将会创建 MapperFactoryBean,之后自动装配。但是,如果你使 用了一个 以上的 DataSource ,那 么自动 装配可 能会失效 。这种 情况下 ,你可 以使用 sqlSessionFactoryBeanName 或 sqlSessionTemplateBeanName 属性来设置正确的 bean 名 称来使用。这就是它如何来配置的,注意 bean 的名称是必须的,而不是 bean 的引用,因 此,value 属性在这里替代通常的 ref:

<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />

MapperScannerConfigurer 支 持 过 滤 由 指 定 的 创 建 接 口 或 注 解 创 建 映 射 器 。 annotationClass 属性指定了要寻找的注解名称。 markerInterface 属性指定了要寻找的父 接口。如果两者都被指定了,加入到接口中的映射器会匹配两种标准。默认情况下,这两个 属性都是 null,所以在基包中给定的所有接口可以作为映射器加载。

被发现的映射器将会使用 Spring 对自动侦测组件(参考 Spring 手册的 3.14.4)默认的命 名策略来命名。也就是说,如果没有发现注解,它就会使用映射器的非大写的非完全限定类 名。但是如果发现了@Component 或 JSR-330 的@Named 注解,它会获取名称。注意你可以 配 置 到 org.springframework.stereotype.Component , javax.inject.Named(如果你使用 JSE 6 的话)或你自己的注解(肯定是自我注解)中,这 样注解将会用作生成器和名称提供器。

接下来让我们看一下MapperScannerConfigurer类的源码 看看是如何自动扫描的。

 1 public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
 2     if (this.processPropertyPlaceHolders) {
 3       processPropertyPlaceHolders();
 4     }
 5 
 6     ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
 7     scanner.setAddToConfig(this.addToConfig);
 8     scanner.setAnnotationClass(this.annotationClass);
 9     scanner.setMarkerInterface(this.markerInterface);
10     scanner.setSqlSessionFactory(this.sqlSessionFactory);
11     scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
12     scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
13     scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
14     scanner.setResourceLoader(this.applicationContext);
15     scanner.setBeanNameGenerator(this.nameGenerator);
16     scanner.registerFilters();
17     scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
18   }

把Mapper接口转换成MapperFactoryBean的代码在地17行这个方法里,让我们跟踪进去看一下。

 1   @Override
 2   public Set<BeanDefinitionHolder> doScan(String... basePackages) {
 3     Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
 4 
 5     if (beanDefinitions.isEmpty()) {
 6       logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
 7     } else {
 8       for (BeanDefinitionHolder holder : beanDefinitions) {
 9         GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();
10 
11         if (logger.isDebugEnabled()) {
12           logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName() 
13               + "' and '" + definition.getBeanClassName() + "' mapperInterface");
14         }
15 
16         // the mapper interface is the original class of the bean
17         // but, the actual class of the bean is MapperFactoryBean
18         //把接口的类型设置进去
19         definition.getPropertyValues().add("mapperInterface", definition.getBeanClassName());
20         //设置Bean的真实类型MapperFactoryBean 
21         definition.setBeanClass(MapperFactoryBean.class);
22         //是否把Mapper接口加入到Mybatis的Config当中去
23         definition.getPropertyValues().add("addToConfig", this.addToConfig);
24 
25         boolean explicitFactoryUsed = false;
26         //如果sqlSessionFactoryBeanName的名字不为空 则在Spring容器中查询
27         //适合多数据源
28         if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
29           definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
30           explicitFactoryUsed = true;
31         } else if (this.sqlSessionFactory != null) {
32           definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
33           explicitFactoryUsed = true;
34         }
35 
36         //如果sqlSessionTemplateBeanName的名字不为空 则在Spring容器中查询
37         //适合多数据源
38         if (StringUtils.ha
39         if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
40           if (explicitFactoryUsed) {
41             logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
42           }
43           definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
44           explicitFactoryUsed = true;
45         } else if (this.sqlSessionTemplate != null) {
46           if (explicitFactoryUsed) {
47             logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
48           }
49           definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
50           explicitFactoryUsed = true;
51         }
52 
53         if (!explicitFactoryUsed) {
54           if (logger.isDebugEnabled()) {
55             logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
56           }
57           definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
58         }
59       }
60     }
61     //这个集合返回以后 Spring容器会将里面的所有内容注册到容器中
62     return beanDefinitions;
63   }


-----------------------

另外一个介绍:

没有必要在Spring的XML配置文件 中注册所有的映射器。相反,你可以使用一个MapperScannerConfigurer,它将会查找类路径下的映射器并自动将它们创建成 MapperFactoryBeans。要创建MapperScannerConfigurer,可以在Spring的配置中添加如下代码:

  1. <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  2.     <propery name="basePackage" value="org.mybatis.spring.sample.mapper"/>
  3. </bean>

basePackage属性是让你为映射器接口文件设置基本的包路径。你可以使用分号或逗号作为分隔符设置多于一个的包路径。每个映射器将会在指定的包路径中递归地被搜索到。

注 意,没有必要去指定SqlSessionFactory或SqlSessionTemplate,因为MapperScannerConfigurer将 会创建MapperFactoryBean,之后自动装配。但是,如果你使用了一个以上的DataSource(因此,也是多个的 SqlSessionFactory),那么自动装配可能会失效。这种情况下,你可以使用sqlSessionFactory或 sqlSessionTemplate属性来设置正确的工厂/模板。

MapperScannerConfigurer支持过滤由指定的创建 接口或注解创建映射器。annotationClass属性指定了要寻找的注解名称。markerInterface属性指定了要寻找的父接口。如果两者 都被指定了,加入到接口中的映射器会匹配两种标准。默认情况下,这两个属性都是null,所以在基包中给定的所有接口可以作为映射器加载。

被发现的映射器将会使用Spring对自动侦测组件默认的命名策略来命名。也就是说,如果没有发现注解,它就会使用映射器的非大写的非完全限定类名。但是如果发现了@Component或JSR-330@Named注解,它会获取名称

 

来源:http://www.tuicool.com/articles/BbAz6v

mybatis集成spring的事务管理

第一 创建一个测试实体

  1. public class Order {
  2.     private int id;
  3.     private String orderName;
  4.     public Order(String orderName) {
  5.         this.orderName = orderName;
  6.     }
  7.     public int getId() {
  8.         return id;
  9.     }
  10.     public void setId(int id) {
  11.         this.id = id;
  12.     }
  13.     public String getOrderName() {
  14.         return orderName;
  15.     }
  16.     public void setOrderName(String orderName) {
  17.         this.orderName = orderName;
  18.     }
  19. }

第二 创建映射器以及对应的xml

只是做了一个简单的订单映射

Java代码  收藏代码
  1. public interface OrderMapper {
  2.     void insertOrder(Order order);
  3. }

 

Xml代码  收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  4. <mapper namespace="com.sagaware.mapper.OrderMapper">
  5. <!-- 开启缓存 -->
  6.   <cache />
  7.   <insert id="insertOrder" parameterType="Order" keyProperty="id"        useGeneratedKeys="true">
  8.     insert into tb_order(name) values (#{orderName})
  9.   </insert>
  10. </mapper>

第三步 写一个service类

  1. @Service("orderService")
  2. public class OrderService {
  3.     @Autowired
  4.     private OrderMapper mapper;
  5.     /**
  6.      * 事务处理必需抛出异常 spring 才会帮事务回滚
  7.      * @param orders
  8.      */
  9.     @Transactional
  10.     public void insertOrder(List<Order> orders) {
  11.         for(int i = 0 ; i < orders.size() ; i++) {
  12.             if(i < 2) {
  13.                 mapper.insertOrder(orders.get(i));
  14.             } else {
  15.                 throw new RuntimeException();
  16.         <pre name="code" class="java"></pre>    }
  17. <br>        }
  18. <br>    }
  19. <br>

第四部 也就是重点,配置spring配置文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
  4.     xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
  5.     xmlns:context="http://www.springframework.org/schema/context"
  6.     xsi:schemaLocation="
  7.      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
  8.      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  9.      http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
  10.      http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
  11.      http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
  12.     <!-- 数据源 -->
  13.     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
  14.         <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
  15.         <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
  16.         <property name="user" value="root"></property>
  17.         <property name="password" value="root"></property>
  18.     </bean>
  19.     <!-- 开启注解配置 -->
  20.     <context:annotation-config />
  21.     <!-- 扫描service层 -->
  22.     <context:component-scan base-package="com.sagaware.service" />
  23.     <!-- 开启事务注解驱动 -->
  24.     <tx:annotation-driven />
  25.     <!-- 事务管理器 -->
  26.     <bean id="transactionManager"
  27.         class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  28.         <property name="dataSource" ref="dataSource" />
  29.     </bean>
  30.     <!-- 创建SqlSessionFactory -->
  31.     <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  32.         <property name="dataSource" ref="dataSource" />
  33.         <property name="typeAliasesPackage" value="com.sagaware.entity" />
  34.     </bean>
  35.     <!-- 自动扫描映射器 -->
  36.     <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  37.         <property name="basePackage" value="com.sagaware.mapper" />
  38.     </bean>
  39. </beans>

最后 写一个测试类

  1. public class Main {
  2.     public static void main(String[] args) {
  3.         ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  4.         OrderService service = (OrderService) context.getBean("orderService");
  5.         System.out.println(service);
  6.         List<Order> orders = new ArrayList<Order>();
  7.         for(int i = 0 ; i < 5 ; i++) {
  8.             Order order = new Order("订单" + i);
  9.             orders.add(order);
  10.         }
  11.         service.insertOrder(orders);
  12.     }
  13. }

MyBatis一对多和多对一

在MyBatis3的过程中,文档上面一直在强调一个id的东西!在做这个实验的时候,也因为没有理解清楚id含义而导致一对多的“多”中也只有一条数据。id和result的唯一不同是id表示的结果将是当比较对象实例时用到的标识属性。这帮助来改进整体表现,特别是缓存和嵌入结果映射。所以不同数据的id应该唯一区别,不然导致数据结果集只有一条数据。

一、表

orders

建表语句:

CREATE TABLE `orders` (
`o_id` int(11) NOT NULL AUTO_INCREMENT,
`pid` int(11) DEFAULT NULL,
`price` decimal(11,0) DEFAULT NULL,
PRIMARY KEY (`o_id`),
UNIQUE KEY `o_id` (`o_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

persons

建表语句:

CREATE TABLE `person` (
`p_id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
PRIMARY KEY (`p_id`),
UNIQUE KEY `p_id` (`p_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

二、实体

1.person

package com.kerwin.mybatis.pojo;

import java.util.List;

public class Person {

private int id;
private String name;
private List<Orders> orderList;

public int getId() {
return id;
}

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

public String getName() {
return name;
}

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

public List<Orders> getOrderList() {
return orderList;
}

public void setOrderList(List<Orders> orderList) {
this.orderList = orderList;
}

@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + "]";
}

public Person() {
super();
// TODO Auto-generated constructor stub
}

public Person(int id, String name, List<Orders> orderList) {
super();
this.id = id;
this.name = name;
this.orderList = orderList;
}

}

2.order

package com.kerwin.mybatis.pojo;public class Orders {
private int id;
private double price;
private Person person;public Person getPerson() {
return person;
}public void setPerson(Person person) {
this.person = person;
}public int getId() {
return id;
}public void setId(int id) {
this.id = id;
}public double getPrice() {
return price;
}public void setPrice(double price) {
this.price = price;
}

@Override
public String toString() {
return "Orders [id=" + id + ", price=" + price + "]";
}

public Orders() {
super();
// TODO Auto-generated constructor stub
}

}

三、映射mapper文件

1. PersonMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sinosig.xb.db.demo.dao.PersonMapper">
<resultMap id="BaseResultMap" type="com.sinosig.xb.db.demo.dao.model.Person">
<id column="p_id" property="pId" jdbcType="INTEGER" />
<result column="name" property="name" jdbcType="VARCHAR" />
</resultMap><resultMap type="com.sinosig.xb.db.demo.dao.model.Person" id="personreSultMap">
<id column="p_id" property="pId" />
<result column="name" property="name" />
<collection property="orderList"
ofType="com.sinosig.xb.db.demo.dao.model.Orders" column="pid">
<id column="o_id" property="oId" />
<result column="price" property="price" />
</collection>
</resultMap>

<select id="selectPersonFetchOrder" parameterType="int"
resultMap="personreSultMap">
select p.*,o.* from person p,orders o where o.pid=p.p_id and
p.p_id=#{id}
</select>

<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" suffix=")" prefixOverrides="and">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value}
and
#{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach collection="criterion.value" item="listItem"
open="(" close=")" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria"
separator="or">
<if test="criteria.valid">
<trim prefix="(" suffix=")" prefixOverrides="and">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value}
and
#{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach collection="criterion.value" item="listItem"
open="(" close=")" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List">
p_id, name
</sql>
<select id="selectByExample" resultMap="BaseResultMap"
parameterType="com.sinosig.xb.db.demo.dao.model.PersonExample">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from person
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" resultMap="BaseResultMap"
parameterType="java.lang.Integer">
select
<include refid="Base_Column_List" />
from person
where p_id = #{pId,jdbcType=INTEGER}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
delete from person
where p_id = #{pId,jdbcType=INTEGER}
</delete>
<delete id="deleteByExample" parameterType="com.sinosig.xb.db.demo.dao.model.PersonExample">
delete from person
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="com.sinosig.xb.db.demo.dao.model.Person">
insert into person (p_id,
name)
values (#{pId,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="com.sinosig.xb.db.demo.dao.model.Person">
insert into person
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="pId != null">
p_id,
</if>
<if test="name != null">
name,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="pId != null">
#{pId,jdbcType=INTEGER},
</if>
<if test="name != null">
#{name,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="com.sinosig.xb.db.demo.dao.model.PersonExample"
resultType="java.lang.Integer">
select count(*) from person
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update person
<set>
<if test="record.pId != null">
p_id = #{record.pId,jdbcType=INTEGER},
</if>
<if test="record.name != null">
name = #{record.name,jdbcType=VARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update person
set p_id = #{record.pId,jdbcType=INTEGER},
name =
#{record.name,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="com.sinosig.xb.db.demo.dao.model.Person">
update person
<set>
<if test="name != null">
name = #{name,jdbcType=VARCHAR},
</if>
</set>
where p_id = #{pId,jdbcType=INTEGER}
</update>
<update id="updateByPrimaryKey" parameterType="com.sinosig.xb.db.demo.dao.model.Person">
update person
set
name = #{name,jdbcType=VARCHAR}
where p_id = #{pId,jdbcType=INTEGER}
</update>
</mapper>

2. OrdersMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.kerwin.mybatis.pojo.Orders">
<resultMap type="com.kerwin.mybatis.pojo.Orders" id="OrdersResultMap">
<id column="o_id" property="id"/>
<result column="price" property="price"/>
<association property="person" javaType="com.kerwin.mybatis.pojo.Person">
<id column="p_id" property="id"/>
<result column="name" property="name"/>
</association>
</resultMap><select id="selectOrdersFetchPerson" resultMap="OrdersResultMap">
select p.*,o.* from person p,orders o where o.pid=p.p_id and o.o_id=#{id}
</select></mapper>

3.sqlMapConfig.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><typeAliases>
<typeAlias type="com.kerwin.mybatis.pojo.Author" alias="Author"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/kerwin/mybatis/pojo/AuthorMapper.xml"/>
<mapper resource="com/kerwin/mybatis/pojo/PostMapper.xml"/>
<mapper resource="com/kerwin/mybatis/pojo/PersonMapper.xml"/>
<mapper resource="com/kerwin/mybatis/pojo/OrdersMapper.xml"/>
</mappers>
</configuration>

四。测试类

/**
*
*/
package com.kerwin.mybatis.test;import java.io.InputStream;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.BeforeClass;
import org.junit.Test;import com.kerwin.mybatis.pojo.Orders;
import com.kerwin.mybatis.pojo.Person;/**
* @author Administrator
*
*/
public class PersonAndOrderTest {private static SqlSessionFactory sessionFactory;/**
* @throws java.lang.Exception
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception {
SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
sessionFactory = factoryBuilder.build(inputStream);}

//一对多,查询person(一)级联查询订单order(多)
@Test
public void testSelectPersonFetchOrder() throws Exception {
SqlSession session = sessionFactory.openSession();
Person person = session.selectOne("com.kerwin.mybatis.pojo.Person.selectPersonFetchOrder", 1);
System.out.println(person);
System.out.println(person.getOrderList().size());
for(Orders orders : person.getOrderList()){
System.out.println(orders);
}
session.close();
}

//多对一,查询订单order(多)级联查询person(一)
@Test
public void testSelectOrdersFetchPerson() throws Exception{
SqlSession session = sessionFactory.openSession();
Orders orders = session.selectOne("com.kerwin.mybatis.pojo.Orders.selectOrdersFetchPerson", 1);
System.out.println(orders);
System.out.println(orders.getPerson());
session.close();
}

}

五、测试结果

1.一对多,查询person(一)级联查询订单order(多)

2.多对一,查询订单order(多)级联查询person(一)

注意:两张表中的主键id字段名要唯一,例如不能都写id,不然的话,在一对多查询的时候就会出现:级联出来的订单项只有一条记录。我之前就是将两张表的主键id字段名都写为id,导致测试结果级联出来的多一直只有一条数据,具体如下:

Spring事务配置的五种方式

前段时间对Spring的事务配置做了比较深入的研究,在此之间对Spring的事务配置虽说也配置过,但是一直没有一个清楚的认识。通过这次的学习发觉Spring的事务配置只要把思路理清,还是比较好掌握的。

总结如下:

Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource、TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分。

DataSource、TransactionManager这两部分只是会根据数据访问方式有所变化,比如使用Hibernate进行数据访问时,DataSource实际为SessionFactory,TransactionManager的实现为HibernateTransactionManager。

具体如下图:

Spring事务配置 (2)

根据代理机制的不同,总结了五种Spring事务的配置方式,配置文件如下:

第一种方式:每个Bean都有一个代理

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-2.5.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"><bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
</bean><!-- 定义事务管理器(声明式的事务) -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

<!-- 配置DAO -->
<bean id="userDaoTarget" class="com.bluesky.spring.dao.UserDaoImpl">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

<bean id="userDao"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!-- 配置事务管理器 -->
<property name="transactionManager" ref="transactionManager" />
<property name="target" ref="userDaoTarget" />
<property name="proxyInterfaces" value="com.bluesky.spring.dao.GeneratorDao" />
<!-- 配置事务属性 -->
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
</beans>

第二种方式:所有Bean共享一个代理基类

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-2.5.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"><bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
</bean><!-- 定义事务管理器(声明式的事务) -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

<bean id="transactionBase"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
lazy-init="true" abstract="true">
<!-- 配置事务管理器 -->
<property name="transactionManager" ref="transactionManager" />
<!-- 配置事务属性 -->
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>

<!-- 配置DAO -->
<bean id="userDaoTarget" class="com.bluesky.spring.dao.UserDaoImpl">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

<bean id="userDao" parent="transactionBase" >
<property name="target" ref="userDaoTarget" />
</bean>
</beans>

第三种方式:使用拦截器

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-2.5.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"><bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
</bean><!-- 定义事务管理器(声明式的事务) -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager" />
<!-- 配置事务属性 -->
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>

<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>*Dao</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</property>
</bean>

<!-- 配置DAO -->
<bean id="userDao" class="com.bluesky.spring.dao.UserDaoImpl">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>

第四种方式:使用tx标签配置的拦截器

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-2.5.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"><context:annotation-config />
<context:component-scan base-package="com.bluesky" /><bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
</bean>

<!-- 定义事务管理器(声明式的事务) -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>

<aop:config>
<aop:pointcut id="interceptorPointCuts"
expression="execution(* com.bluesky.spring.dao.*.*(..))" />
<aop:advisor advice-ref="txAdvice"
pointcut-ref="interceptorPointCuts" />
</aop:config>
</beans>

第五种方式:全注解

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-2.5.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"><context:annotation-config />
<context:component-scan base-package="com.bluesky" /><tx:annotation-driven transaction-manager="transactionManager"/>

<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
</bean>

<!-- 定义事务管理器(声明式的事务) -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

</beans>

此时在DAO上需加上@Transactional注解,如下:

package com.bluesky.spring.dao;

import java.util.List;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Component;

import com.bluesky.spring.domain.User;

@Transactional
@Component("userDao")
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {

public List<User> listUsers() {
return this.getSession().createQuery("from User").list();
}


}

来源:http://www.blogjava.net/robbie/archive/2009/04/05/264003.html

Slick编程简介

Slick对于Scala来说,有如LINQ至于C# ,或者类似于其它平台上的ORM系统,它使用应用使用数据库有如使用Scala内置的集合类型(比如列表,集合等)一样方便。当然如有需要你还是可以直接使用SQL语句来查询数据库。
下面为使用Slick的代码片段:
1    val limit = 10.0
2
3    // Your query could look like this:
4    ( for( c <- coffees; if c.price < limit ) yield c.name ).list
5
6    // Or using more plain SQL String Interpolation:
7    sql"select COF_NAME from COFFEES where PRICE < $limit".as[String].list
8
9    // Both queries result in SQL equivalent to:
10    // select COF_NAME from COFFEES where PRICE < 10.0

使用Slick而不直接使用SQL语句,可以使用编译器帮助发现一些类型错误,同时Slick可以为不同的后台数据库类型生成查询。
它具有如下的一些特定:
Scala
所有查询,表格和字段映射,以及类型都采用普通的Scala语法。
1    class Coffees(tag: Tag) extends Table[(String, Double)](tag, "COFFEES") {
2      def name = column[String]("COF_NAME", O.PrimaryKey)
3      def price = column[Double]("PRICE")
4      def * = (name, price)
5    }
6    val coffees = TableQuery[Coffees]

数据访问接口类型Scala的集合类型
1    // Query that only returns the "name" column
2    coffees.map(_.name)
3
4    // Query that does a "where price < 10.0"
5    coffees.filter(_.price < 10.0)

类型安全
你使用的IDE可以帮助你写代码
在编译时而无需到运行时就可以发现一些错误
1    // The result of "select PRICE from COFFEES" is a Seq of Double
2    // because of the type safe column definitions
3    val coffeeNames: Seq[Double] = coffees.map(_.price).list
4
5    // Query builders are type safe:
6    coffees.filter(_.price < 10.0)
7    // Using a string in the filter would result in a compilation error

可以组合
查询接口为函数,这些函数可以多次组合和重用。
1    // Create a query for coffee names with a price less than 10, sorted by name
2    coffees.filter(_.price < 10.0).sortBy(_.name).map(_.name)
3    // The generated SQL is equivalent to:
4    // select name from COFFEES where PRICE < 10.0 order by NAME

支持的数据库系统

  • DB2 (via slick-extensions)
  • Derby/JavaDB
  • H2
  • HSQLDB/HyperSQL
  • Microsoft Access
  • Microsoft SQL Server (via slick-extensions)
  • MySQL
  • Oracle (via slick-extensions)
  • PostgreSQL
  • SQLite

对于其它的一些数据库类型Slick也提供了有限的支持。

查询接口Lifted Embedding
Sclick 使用Lifted Embedding作为标准的数据库查询接口,此外Direct Embedding接口正在开发测试当中。
Lifted Embedding的名称来自于,你不是使用标准的Scala数据类型来访问查询数据库,而是使用Rep构造器来提升(Lift)Scala的基本数据类型,然后使用提升后的数据类

型来访问数据库,比如标准的Scala集合的例子:
1    case class Coffee(name: String, price: Double)
2    val coffees: List[Coffee] = //...
3
4    val l = coffees.filter(_.price > 8.0).map(_.name)
5    //                       ^       ^          ^
6    //                       Double  Double     String

而对应的提升之后的例子:
1    class Coffees(tag: Tag) extends Table[(String, Double)](tag, "COFFEES") {
2      def name = column[String]("COF_NAME")
3      def price = column[Double]("PRICE")
4      def * = (name, price)
5    }
6    val coffees = TableQuery[Coffees]
7
8    val q = coffees.filter(_.price > 8.0).map(_.name)
9    //                       ^       ^          ^
10    //               Rep[Double]  Rep[Double]  Rep[String]

所有的基本Scala类型,都提升为Rep。即使是8.0字面量也被提升为Rep[Double]类型。
后面的例子,我们会采用Chinook数据库作为例子。

Chinook 数据库模型。

Chinook数据库前身为著名的Northwind数据库,它的数据模型如下:

ChinookDatabaseSchema1.1

 

Slick 编程(2): 准备开发环境

本篇介绍如果设置使用Slick的Scala开发环境,这里我们使用SBT命令行,SBT使用的目录结构和Maven一样,我们可以创建一个目录,比如Slick,然后创建如下的缺省目录结构:

src
main
java
resources
scala
test
java
resources
scala

因为我们打算使用MySQL数据库,并使用Slick来访问数据库,因此我们在Slick的根目录下创建一个build.sbt,添加相关引用:
1    name := "Scala Slick Examples"
2
3    version := "1.0"
4
5    scalaVersion := "2.10.4"
6
7    libraryDependencies += "com.typesafe.slick" %% "slick" % "2.0.2"
8
9    libraryDependencies += "org.slf4j" % "slf4j-nop" % "1.6.4"
10
11    libraryDependencies += "mysql" % "mysql-connector-java" % "5.1.18"

Slick使用SLF4J 作为日志库文件。
我们的MySQL数据库 Chinook 安装在本地服务器上面,我们在使用Slick可以手工创建数据库表Schema的定义,也可以使用自动代码生成工具从已有的数据库创建Table的Schema定义。
我们在命令行输入 sbt ,进入SBT控制台。
然后我们使用console,进入Scala控制台,注意此时SBT自动把build.sbt中引用到的库比如slick, mysql添加到Scala控制台,我们使用如下命令:
1    scala.slick.model.codegen.SourceCodeGenerator.main(
2      Array(slickDriver, jdbcDriver, url, outputFolder, pkg, user, password)
3    )

相关参数如下:
slickDriver Fully qualified name of Slick driver class, e.g. “scala.slick.driver.H2Driver”
jdbcDriver Fully qualified name of jdbc driver class, e.g. “org.h2.Driver”
url jdbc url, e.g. “jdbc:postgresql://localhost/test”
outputFolder Place where the package folder structure should be put
pkg Scala package the generated code should be places in
user database connection user name
password database connection password

例如对于本例,我们使用mysql数据库,可以在命令行输入如下命令:注意修改你的用户名和密码:
1    scala.slick.model.codegen.SourceCodeGenerator.main(
2      Array("scala.slick.driver.MySQLDriver", "com.mysql.jdbc.Driver",
3      "jdbc:mysql://127.0.0.1/Chinook",
4      "./src/main/scala",
5      "com.guidebee.slick.example", "user", "password")
6    )

这样自动代码生成工具,就在/src/main/scala目录下生成了Tables.scala文件
1    package com.guidebee.slick.example
2    // AUTO-GENERATED Slick data model
3    /** Stand-alone Slick data model for immediate use */
4    object Tables extends {
5      val profile = scala.slick.driver.MySQLDriver
6    } with Tables
7
8    /** Slick data model trait for extension, choice of backend or usage in the cake pattern. (Make sure to initialize this late.) */
9    trait Tables {
10      val profile: scala.slick.driver.JdbcProfile
11      import profile.simple._
12      import scala.slick.model.ForeignKeyAction
13      // NOTE: GetResult mappers for plain SQL are only generated for tables where Slick knows how to map the types of all columns.
14      import scala.slick.jdbc.{GetResult => GR}
15
16      /** DDL for all tables. Call .create to execute. */
17      lazy val ddl = Album.ddl ++ Artist.ddl ++ Customer.ddl ++ Employee.ddl ++ Genre.ddl ++ Invoice.ddl ++ Invoiceline.ddl ++ Mediatype.ddl ++ Playlist.ddl ++ Playlisttrack.ddl ++ Track.ddl
18
19      /** Entity class storing rows of table Album
20       *  @param albumid Database column AlbumId PrimaryKey
21       *  @param title Database column Title
22       *  @param artistid Database column ArtistId  */
23      case class AlbumRow(albumid: Int, title: String, artistid: Int)
24      /** GetResult implicit for fetching AlbumRow objects using plain SQL queries */
25      implicit def GetResultAlbumRow(implicit e0: GR[Int], e1: GR[String]):GR[AlbumRow] = GR{
26        prs => import prs._
27        AlbumRow.tupled((<<[Int], <<[String], <<[Int]))
28      }
29      /** Table description of table Album. Objects of this class serve as prototypes for rows in queries. */
30      class Album(tag: Tag) extends Table[AlbumRow](tag, "Album") {
31        def * = (albumid, title, artistid) <> (AlbumRow.tupled, AlbumRow.unapply)
32        /** Maps whole row to an option. Useful for outer joins. */
33        def ? = (albumid.?, title.?, artistid.?).shaped.<>({r=>import r._;_1.map(_=> AlbumRow.tupled((_1.get, _2.get, _3.get)))}, (_:Any) => throw new Exception("Inserting into ? projection not supported."))
34
35        /** Database column AlbumId PrimaryKey */
36        val albumid: Column[Int] = column[Int]("AlbumId", O.PrimaryKey)
37        /** Database column Title  */
38        val title: Column[String] = column[String]("Title")
39        /** Database column ArtistId  */
40        val artistid: Column[Int] = column[Int]("ArtistId")
41
42        /** Foreign key referencing Artist (database name FK_AlbumArtistId) */
43        lazy val artistFk = foreignKey("FK_AlbumArtistId", artistid, Artist)(r => r.artistid, onUpdate=ForeignKeyAction.NoAction, onDelete=ForeignKeyAction.NoAction)
44      }
45      /** Collection-like TableQuery object for table Album */
46      lazy val Album = new TableQuery(tag => new Album(tag))
47
48      /** Entity class storing rows of table Artist
49       *  @param artistid Database column ArtistId PrimaryKey
50       *  @param name Database column Name  */
51      case class ArtistRow(artistid: Int, name: Option[String])
52      /** GetResult implicit for fetching ArtistRow objects using plain SQL queries */
53      implicit def GetResultArtistRow(implicit e0: GR[Int], e1:GR[Option[String]]): GR[ArtistRow] = GR{
54        prs => import prs._
55        ArtistRow.tupled((<<[Int], <<?[String]))
56      }
57      /** Table description of table Artist. Objects of this class serve as prototypes for rows in queries. */
58      class Artist(tag: Tag) extends Table[ArtistRow](tag, "Artist") {
59        def * = (artistid, name) <> (ArtistRow.tupled, ArtistRow.unapply)
60        /** Maps whole row to an option. Useful for outer joins. */
61        def ? = (artistid.?, name).shaped.<>({r=>import r._; _1.map(_=> ArtistRow.tupled((_1.get, _2)))}, (_:Any) =>  throw newException("Inserting into ? projection not supported."))
62
63        /** Database column ArtistId PrimaryKey */
64        val artistid: Column[Int] = column[Int]("ArtistId", O.PrimaryKey)
65        /** Database column Name  */
66        val name: Column[Option[String]] = column[Option[String]]("Name")
67      }
68      /** Collection-like TableQuery object for table Artist */
69      lazy val Artist = new TableQuery(tag => new Artist(tag))
70
71      /** Entity class storing rows of table Customer
72       *  @param customerid Database column CustomerId PrimaryKey
73       *  @param firstname Database column FirstName
74       *  @param lastname Database column LastName
75       *  @param company Database column Company
76       *  @param address Database column Address
77       *  @param city Database column City
78       *  @param state Database column State
79       *  @param country Database column Country
80       *  @param postalcode Database column PostalCode
81       *  @param phone Database column Phone
82       *  @param fax Database column Fax
83       *  @param email Database column Email
84       *  @param supportrepid Database column SupportRepId  */
85      case class CustomerRow(customerid: Int, firstname: String, lastname:String, company: Option[String], address: Option[String], city:Option[String], state: Option[String], country: Option[String], postalcode: Option[String], phone: Option[String], fax: Option[String], email: String, supportrepid: Option[Int])
86      /** GetResult implicit for fetching CustomerRow objects using plain SQL queries */
87      implicit def GetResultCustomerRow(implicit e0: GR[Int], e1:GR[String], e2: GR[Option[String]], e3: GR[Option[Int]]):GR[CustomerRow] = GR{
88        prs => import prs._
89        CustomerRow.tupled((<<[Int], <<[String], <<[String], <<?[String], <<?[String], <<?[String], <<?[String], <<?[String], <<?[String], <<?[String], <<?[String], <<[String], <<?[Int]))
90      }
91      /** Table description of table Customer. Objects of this class serve as prototypes for rows in queries. */
92      class Customer(tag: Tag) extends Table[CustomerRow](tag, "Customer") {
93        def * = (customerid, firstname, lastname, company, address, city, state, country, postalcode, phone, fax, email, supportrepid) <> (CustomerRow.tupled, CustomerRow.unapply)
94        /** Maps whole row to an option. Useful for outer joins. */
95        def ? = (customerid.?, firstname.?, lastname.?, company, address, city, state, country, postalcode, phone, fax, email.?, supportrepid).shaped.<>({r=>import r._; _1.map(_=> CustomerRow.tupled((_1.get, _2.get, _3.get, _4, _5, _6, _7, _8, _9,_10, _11, _12.get, _13)))}, (_:Any) =>  throw new Exception("Inserting into ? projection not supported."))
96
97        /** Database column CustomerId PrimaryKey */
98        val customerid: Column[Int] = column[Int]("CustomerId", O.PrimaryKey)
99        /** Database column FirstName  */
100        val firstname: Column[String] = column[String]("FirstName")
101        /** Database column LastName  */
102        val lastname: Column[String] = column[String]("LastName")
103        /** Database column Company  */
104        val company: Column[Option[String]] = column[Option[String]]("Company")
105        /** Database column Address  */
106        val address: Column[Option[String]] = column[Option[String]]("Address")
107        /** Database column City  */
108        val city: Column[Option[String]] = column[Option[String]]("City")
109        /** Database column State  */
110        val state: Column[Option[String]] = column[Option[String]]("State")
111        /** Database column Country  */
112        val country: Column[Option[String]] = column[Option[String]]("Country")
113        /** Database column PostalCode  */
114        val postalcode: Column[Option[String]] = column[Option[String]]("PostalCode")
115        /** Database column Phone  */
116        val phone: Column[Option[String]] = column[Option[String]]("Phone")
117        /** Database column Fax  */
118        val fax: Column[Option[String]] = column[Option[String]]("Fax")
119        /** Database column Email  */
120        val email: Column[String] = column[String]("Email")
121        /** Database column SupportRepId  */
122        val supportrepid: Column[Option[Int]] = column[Option[Int]]("SupportRepId")
123
124        /** Foreign key referencing Employee (database name FK_CustomerSupportRepId) */
125        lazy val employeeFk = foreignKey("FK_CustomerSupportRepId", supportrepid, Employee)(r => r.employeeid, onUpdate=ForeignKeyAction.NoAction, onDelete=ForeignKeyAction.NoAction)
126      }
127      /** Collection-like TableQuery object for table Customer */
128      lazy val Customer = new TableQuery(tag => new Customer(tag))
129
130      /** Entity class storing rows of table Employee
131       *  @param employeeid Database column EmployeeId PrimaryKey
132       *  @param lastname Database column LastName
133       *  @param firstname Database column FirstName
134       *  @param title Database column Title
135       *  @param reportsto Database column ReportsTo
136       *  @param birthdate Database column BirthDate
137       *  @param hiredate Database column HireDate
138       *  @param address Database column Address
139       *  @param city Database column City
140       *  @param state Database column State
141       *  @param country Database column Country
142       *  @param postalcode Database column PostalCode
143       *  @param phone Database column Phone
144       *  @param fax Database column Fax
145       *  @param email Database column Email  */
146      case class EmployeeRow(employeeid: Int, lastname: String, firstname:String, title: Option[String], reportsto: Option[Int], birthdate:Option1, hiredate: Option1, address: Option[String], city:Option[String], state: Option[String], country: Option[String], postalcode: Option[String], phone: Option[String], fax: Option[String], email: Option[String])
147      /** GetResult implicit for fetching EmployeeRow objects using plain SQL queries */
148      implicit def GetResultEmployeeRow(implicit e0: GR[Int], e1:GR[String], e2: GR[Option[String]], e3: GR[Option[Int]], e4:GR[Option1]): GR[EmployeeRow] = GR{
149        prs => import prs._
150        EmployeeRow.tupled((<<[Int], <<[String], <<[String], <<?[String], <<?[Int], <<?1, <<?1, <<?[String], <<?[String], <<?[String], <<?[String], <<?[String], <<?[String], <<?[String], <<?[String]))
151      }
152      /** Table description of table Employee. Objects of this class serve as prototypes for rows in queries. */
153      class Employee(tag: Tag) extends Table[EmployeeRow](tag, "Employee") {
154        def * = (employeeid, lastname, firstname, title, reportsto, birthdate, hiredate, address, city, state, country, postalcode, phone, fax, email) <> (EmployeeRow.tupled, EmployeeRow.unapply)
155        /** Maps whole row to an option. Useful for outer joins. */
156        def ? = (employeeid.?, lastname.?, firstname.?, title, reportsto, birthdate, hiredate, address, city, state, country, postalcode, phone, fax, email).shaped.<>({r=>import r._; _1.map(_=> EmployeeRow.tupled((_1.get, _2.get, _3.get, _4, _5, _6, _7, _8, _9,_10, _11, _12, _13, _14, _15)))}, (_:Any) =>  throw newException("Inserting into ? projection not supported."))
157
158        /** Database column EmployeeId PrimaryKey */
159        val employeeid: Column[Int] = column[Int]("EmployeeId", O.PrimaryKey)
160        /** Database column LastName  */
161        val lastname: Column[String] = column[String]("LastName")
162        /** Database column FirstName  */
163        val firstname: Column[String] = column[String]("FirstName")
164        /** Database column Title  */
165        val title: Column[Option[String]] = column[Option[String]]("Title")
166        /** Database column ReportsTo  */
167        val reportsto: Column[Option[Int]] = column[Option[Int]]("ReportsTo")
168        /** Database column BirthDate  */
169        val birthdate: Column[Option1] = column[Option1]("BirthDate")
170        /** Database column HireDate  */
171        val hiredate: Column[Option1] = column[Option1]("HireDate")
172        /** Database column Address  */
173        val address: Column[Option[String]] = column[Option[String]]("Address")
174        /** Database column City  */
175        val city: Column[Option[String]] = column[Option[String]]("City")
176        /** Database column State  */
177        val state: Column[Option[String]] = column[Option[String]]("State")
178        /** Database column Country  */
179        val country: Column[Option[String]] = column[Option[String]]("Country")
180        /** Database column PostalCode  */
181        val postalcode: Column[Option[String]] = column[Option[String]]("PostalCode")
182        /** Database column Phone  */
183        val phone: Column[Option[String]] = column[Option[String]]("Phone")
184        /** Database column Fax  */
185        val fax: Column[Option[String]] = column[Option[String]]("Fax")
186        /** Database column Email  */
187        val email: Column[Option[String]] = column[Option[String]]("Email")
188
189        /** Foreign key referencing Employee (database name FK_EmployeeReportsTo) */
190        lazy val employeeFk = foreignKey("FK_EmployeeReportsTo", reportsto, Employee)(r => r.employeeid, onUpdate=ForeignKeyAction.NoAction, onDelete=ForeignKeyAction.NoAction)
191      }
192      /** Collection-like TableQuery object for table Employee */
193      lazy val Employee = new TableQuery(tag => new Employee(tag))
194
195      /** Entity class storing rows of table Genre
196       *  @param genreid Database column GenreId PrimaryKey
197       *  @param name Database column Name  */
198      case class GenreRow(genreid: Int, name: Option[String])
199      /** GetResult implicit for fetching GenreRow objects using plain SQL queries */
200      implicit def GetResultGenreRow(implicit e0: GR[Int], e1:GR[Option[String]]): GR[GenreRow] = GR{
201        prs => import prs._
202        GenreRow.tupled((<<[Int], <<?[String]))
203      }
204      /** Table description of table Genre. Objects of this class serve as prototypes for rows in queries. */
205      class Genre(tag: Tag) extends Table[GenreRow](tag, "Genre") {
206        def * = (genreid, name) <> (GenreRow.tupled, GenreRow.unapply)
207        /** Maps whole row to an option. Useful for outer joins. */
208        def ? = (genreid.?, name).shaped.<>({r=>import r._; _1.map(_=> GenreRow.tupled((_1.get, _2)))}, (_:Any) =>  throw newException("Inserting into ? projection not supported."))
209
210        /** Database column GenreId PrimaryKey */
211        val genreid: Column[Int] = column[Int]("GenreId", O.PrimaryKey)
212        /** Database column Name  */
213        val name: Column[Option[String]] = column[Option[String]]("Name")
214      }
215      /** Collection-like TableQuery object for table Genre */
216      lazy val Genre = new TableQuery(tag => new Genre(tag))
217
218      /** Entity class storing rows of table Invoice
219       *  @param invoiceid Database column InvoiceId PrimaryKey
220       *  @param customerid Database column CustomerId
221       *  @param invoicedate Database column InvoiceDate
222       *  @param billingaddress Database column BillingAddress
223       *  @param billingcity Database column BillingCity
224       *  @param billingstate Database column BillingState
225       *  @param billingcountry Database column BillingCountry
226       *  @param billingpostalcode Database column BillingPostalCode
227       *  @param total Database column Total  */
228      case class InvoiceRow(invoiceid: Int, customerid: Int, invoicedate:java.sql.Timestamp, billingaddress: Option[String], billingcity:Option[String], billingstate: Option[String], billingcountry:Option[String], billingpostalcode: Option[String], total:scala.math.BigDecimal)
229      /** GetResult implicit for fetching InvoiceRow objects using plain SQL queries */
230      implicit def GetResultInvoiceRow(implicit e0: GR[Int], e1: GR1, e2:GR[Option[String]], e3: GR1): GR[InvoiceRow] = GR{
231        prs => import prs._
232        InvoiceRow.tupled((<<[Int], <<[Int], <<1, <<?[String], <<?[String], <<?[String], <<?[String], <<?[String], <<1))
233      }
234      /** Table description of table Invoice. Objects of this class serve as prototypes for rows in queries. */
235      class Invoice(tag: Tag) extends Table[InvoiceRow](tag, "Invoice") {
236        def * = (invoiceid, customerid, invoicedate, billingaddress, billingcity, billingstate, billingcountry, billingpostalcode, total) <> (InvoiceRow.tupled, InvoiceRow.unapply)
237        /** Maps whole row to an option. Useful for outer joins. */
238        def ? = (invoiceid.?, customerid.?, invoicedate.?, billingaddress, billingcity, billingstate, billingcountry, billingpostalcode, total.?).shaped.<>({r=>import r._; _1.map(_=> InvoiceRow.tupled((_1.get, _2.get, _3.get, _4, _5, _6, _7, _8,_9.get)))}, (_:Any) =>  throw new Exception("Inserting into ? projection not supported."))
239
240        /** Database column InvoiceId PrimaryKey */
241        val invoiceid: Column[Int] = column[Int]("InvoiceId", O.PrimaryKey)
242        /** Database column CustomerId  */
243        val customerid: Column[Int] = column[Int]("CustomerId")
244        /** Database column InvoiceDate  */
245        val invoicedate: Column1 = column1("InvoiceDate")
246        /** Database column BillingAddress  */
247        val billingaddress: Column[Option[String]] = column[Option[String]]("BillingAddress")
248        /** Database column BillingCity  */
249        val billingcity: Column[Option[String]] = column[Option[String]]("BillingCity")
250        /** Database column BillingState  */
251        val billingstate: Column[Option[String]] = column[Option[String]]("BillingState")
252        /** Database column BillingCountry  */
253        val billingcountry: Column[Option[String]] = column[Option[String]]("BillingCountry")
254        /** Database column BillingPostalCode  */
255        val billingpostalcode: Column[Option[String]] =column[Option[String]]("BillingPostalCode")
256        /** Database column Total  */
257        val total: Column1 = column1("Total")
258
259        /** Foreign key referencing Customer (database name FK_InvoiceCustomerId) */
260        lazy val customerFk = foreignKey("FK_InvoiceCustomerId", customerid, Customer)(r => r.customerid, onUpdate=ForeignKeyAction.NoAction, onDelete=ForeignKeyAction.NoAction)
261      }
262      /** Collection-like TableQuery object for table Invoice */
263      lazy val Invoice = new TableQuery(tag => new Invoice(tag))
264
265      /** Entity class storing rows of table Invoiceline
266       *  @param invoicelineid Database column InvoiceLineId PrimaryKey
267       *  @param invoiceid Database column InvoiceId
268       *  @param trackid Database column TrackId
269       *  @param unitprice Database column UnitPrice
270       *  @param quantity Database column Quantity  */
271      case class InvoicelineRow(invoicelineid: Int, invoiceid: Int, trackid: Int, unitprice: scala.math.BigDecimal, quantity: Int)
272      /** GetResult implicit for fetching InvoicelineRow objects using plain SQL queries */
273      implicit def GetResultInvoicelineRow(implicit e0: GR[Int], e1: GR1):GR[InvoicelineRow] = GR{
274        prs => import prs._
275        InvoicelineRow.tupled((<<[Int], <<[Int], <<[Int], <<1, <<[Int]))
276      }
277      /** Table description of table InvoiceLine. Objects of this class serve as prototypes for rows in queries. */
278      class Invoiceline(tag: Tag) extends Table[InvoicelineRow](tag,"InvoiceLine") {
279        def * = (invoicelineid, invoiceid, trackid, unitprice, quantity) <> (InvoicelineRow.tupled, InvoicelineRow.unapply)
280        /** Maps whole row to an option. Useful for outer joins. */
281        def ? = (invoicelineid.?, invoiceid.?, trackid.?, unitprice.?, quantity.?).shaped.<>({r=>import r._; _1.map(_=> InvoicelineRow.tupled((_1.get, _2.get, _3.get, _4.get, _5.get)))}, (_:Any) =>  throw new Exception("Inserting into ? projection not supported."))
282
283        /** Database column InvoiceLineId PrimaryKey */
284        val invoicelineid: Column[Int] = column[Int]("InvoiceLineId", O.PrimaryKey)
285        /** Database column InvoiceId  */
286        val invoiceid: Column[Int] = column[Int]("InvoiceId")
287        /** Database column TrackId  */
288        val trackid: Column[Int] = column[Int]("TrackId")
289        /** Database column UnitPrice  */
290        val unitprice: Column1 = column1("UnitPrice")
291        /** Database column Quantity  */
292        val quantity: Column[Int] = column[Int]("Quantity")
293
294        /** Foreign key referencing Invoice (database name FK_InvoiceLineInvoiceId) */
295        lazy val invoiceFk = foreignKey("FK_InvoiceLineInvoiceId", invoiceid, Invoice)(r => r.invoiceid, onUpdate=ForeignKeyAction.NoAction, onDelete=ForeignKeyAction.NoAction)
296        /** Foreign key referencing Track (database name FK_InvoiceLineTrackId) */
297        lazy val trackFk = foreignKey("FK_InvoiceLineTrackId", trackid, Track)(r => r.trackid, onUpdate=ForeignKeyAction.NoAction, onDelete=ForeignKeyAction.NoAction)
298      }
299      /** Collection-like TableQuery object for table Invoiceline */
300      lazy val Invoiceline = new TableQuery(tag => new Invoiceline(tag))
301
302      /** Entity class storing rows of table Mediatype
303       *  @param mediatypeid Database column MediaTypeId PrimaryKey
304       *  @param name Database column Name  */
305      case class MediatypeRow(mediatypeid: Int, name: Option[String])
306      /** GetResult implicit for fetching MediatypeRow objects using plain SQL queries */
307      implicit def GetResultMediatypeRow(implicit e0: GR[Int], e1:GR[Option[String]]): GR[MediatypeRow] = GR{
308        prs => import prs._
309        MediatypeRow.tupled((<<[Int], <<?[String]))
310      }
311      /** Table description of table MediaType. Objects of this class serve as prototypes for rows in queries. */
312      class Mediatype(tag: Tag) extends Table[MediatypeRow](tag,"MediaType") {
313        def * = (mediatypeid, name) <> (MediatypeRow.tupled, MediatypeRow.unapply)
314        /** Maps whole row to an option. Useful for outer joins. */
315        def ? = (mediatypeid.?, name).shaped.<>({r=>import r._; _1.map(_=> MediatypeRow.tupled((_1.get, _2)))}, (_:Any) =>  throw newException("Inserting into ? projection not supported."))
316
317        /** Database column MediaTypeId PrimaryKey */
318        val mediatypeid: Column[Int] = column[Int]("MediaTypeId", O.PrimaryKey)
319        /** Database column Name  */
320        val name: Column[Option[String]] = column[Option[String]]("Name")
321      }
322      /** Collection-like TableQuery object for table Mediatype */
323      lazy val Mediatype = new TableQuery(tag => new Mediatype(tag))
324
325      /** Entity class storing rows of table Playlist
326       *  @param playlistid Database column PlaylistId PrimaryKey
327       *  @param name Database column Name  */
328      case class PlaylistRow(playlistid: Int, name: Option[String])
329      /** GetResult implicit for fetching PlaylistRow objects using plain SQL queries */
330      implicit def GetResultPlaylistRow(implicit e0: GR[Int], e1:GR[Option[String]]): GR[PlaylistRow] = GR{
331        prs => import prs._
332        PlaylistRow.tupled((<<[Int], <<?[String]))
333      }
334      /** Table description of table Playlist. Objects of this class serve as prototypes for rows in queries. */
335      class Playlist(tag: Tag) extends Table[PlaylistRow](tag, "Playlist") {
336        def * = (playlistid, name) <> (PlaylistRow.tupled, PlaylistRow.unapply)
337        /** Maps whole row to an option. Useful for outer joins. */
338        def ? = (playlistid.?, name).shaped.<>({r=>import r._; _1.map(_=> PlaylistRow.tupled((_1.get, _2)))}, (_:Any) =>  throw newException("Inserting into ? projection not supported."))
339
340        /** Database column PlaylistId PrimaryKey */
341        val playlistid: Column[Int] = column[Int]("PlaylistId", O.PrimaryKey)
342        /** Database column Name  */
343        val name: Column[Option[String]] = column[Option[String]]("Name")
344      }
345      /** Collection-like TableQuery object for table Playlist */
346      lazy val Playlist = new TableQuery(tag => new Playlist(tag))
347
348      /** Entity class storing rows of table Playlisttrack
349       *  @param playlistid Database column PlaylistId
350       *  @param trackid Database column TrackId  */
351      case class PlaylisttrackRow(playlistid: Int, trackid: Int)
352      /** GetResult implicit for fetching PlaylisttrackRow objects using plain SQL queries */
353      implicit def GetResultPlaylisttrackRow(implicit e0: GR[Int]):GR[PlaylisttrackRow] = GR{
354        prs => import prs._
355        PlaylisttrackRow.tupled((<<[Int], <<[Int]))
356      }
357      /** Table description of table PlaylistTrack. Objects of this class serve as prototypes for rows in queries. */
358      class Playlisttrack(tag: Tag) extends Table[PlaylisttrackRow](tag,"PlaylistTrack") {
359        def * = (playlistid, trackid) <> (PlaylisttrackRow.tupled, PlaylisttrackRow.unapply)
360        /** Maps whole row to an option. Useful for outer joins. */
361        def ? = (playlistid.?, trackid.?).shaped.<>({r=>import r._;_1.map(_=> PlaylisttrackRow.tupled((_1.get, _2.get)))}, (_:Any) => throw new Exception("Inserting into ? projection not supported."))
362
363        /** Database column PlaylistId  */
364        val playlistid: Column[Int] = column[Int]("PlaylistId")
365        /** Database column TrackId  */
366        val trackid: Column[Int] = column[Int]("TrackId")
367
368        /** Primary key of Playlisttrack (database name PlaylistTrack_PK) */
369        val pk = primaryKey("PlaylistTrack_PK", (playlistid, trackid))
370
371        /** Foreign key referencing Playlist (database name FK_PlaylistTrackPlaylistId) */
372        lazy val playlistFk = foreignKey("FK_PlaylistTrackPlaylistId", playlistid, Playlist)(r => r.playlistid, onUpdate=ForeignKeyAction.NoAction, onDelete=ForeignKeyAction.NoAction)
373        /** Foreign key referencing Track (database name FK_PlaylistTrackTrackId) */
374        lazy val trackFk = foreignKey("FK_PlaylistTrackTrackId", trackid, Track)(r => r.trackid, onUpdate=ForeignKeyAction.NoAction, onDelete=ForeignKeyAction.NoAction)
375      }
376      /** Collection-like TableQuery object for table Playlisttrack */
377      lazy val Playlisttrack = new TableQuery(tag => newPlaylisttrack(tag))
378
379      /** Entity class storing rows of table Track
380       *  @param trackid Database column TrackId PrimaryKey
381       *  @param name Database column Name
382       *  @param albumid Database column AlbumId
383       *  @param mediatypeid Database column MediaTypeId
384       *  @param genreid Database column GenreId
385       *  @param composer Database column Composer
386       *  @param milliseconds Database column Milliseconds
387       *  @param bytes Database column Bytes
388       *  @param unitprice Database column UnitPrice  */
389      case class TrackRow(trackid: Int, name: String, albumid: Option[Int], mediatypeid: Int, genreid: Option[Int], composer: Option[String], milliseconds: Int, bytes: Option[Int], unitprice:scala.math.BigDecimal)
390      /** GetResult implicit for fetching TrackRow objects using plain SQL queries */
391      implicit def GetResultTrackRow(implicit e0: GR[Int], e1: GR[String], e2: GR[Option[Int]], e3: GR[Option[String]], e4: GR1): GR[TrackRow] =GR{
392        prs => import prs._
393        TrackRow.tupled((<<[Int], <<[String], <<?[Int], <<[Int], <<?[Int], <<?[String], <<[Int], <<?[Int], <<1))
394      }
395      /** Table description of table Track. Objects of this class serve as prototypes for rows in queries. */
396      class Track(tag: Tag) extends Table[TrackRow](tag, "Track") {
397        def * = (trackid, name, albumid, mediatypeid, genreid, composer, milliseconds, bytes, unitprice) <> (TrackRow.tupled, TrackRow.unapply)
398        /** Maps whole row to an option. Useful for outer joins. */
399        def ? = (trackid.?, name.?, albumid, mediatypeid.?, genreid, composer, milliseconds.?, bytes, unitprice.?).shaped.<>({r=>import r._;_1.map(_=> TrackRow.tupled((_1.get, _2.get, _3, _4.get, _5, _6, _7.get,_8, _9.get)))}, (_:Any) =>  throw new Exception("Inserting into ? projection not supported."))
400
401        /** Database column TrackId PrimaryKey */
402        val trackid: Column[Int] = column[Int]("TrackId", O.PrimaryKey)
403        /** Database column Name  */
404        val name: Column[String] = column[String]("Name")
405        /** Database column AlbumId  */
406        val albumid: Column[Option[Int]] = column[Option[Int]]("AlbumId")
407        /** Database column MediaTypeId  */
408        val mediatypeid: Column[Int] = column[Int]("MediaTypeId")
409        /** Database column GenreId  */
410        val genreid: Column[Option[Int]] = column[Option[Int]]("GenreId")
411        /** Database column Composer  */
412        val composer: Column[Option[String]] = column[Option[String]]("Composer")
413        /** Database column Milliseconds  */
414        val milliseconds: Column[Int] = column[Int]("Milliseconds")
415        /** Database column Bytes  */
416        val bytes: Column[Option[Int]] = column[Option[Int]]("Bytes")
417        /** Database column UnitPrice  */
418        val unitprice: Column1 = column1("UnitPrice")
419
420        /** Foreign key referencing Album (database name FK_TrackAlbumId) */
421        lazy val albumFk = foreignKey("FK_TrackAlbumId", albumid, Album)(r=> r.albumid, onUpdate=ForeignKeyAction.NoAction, onDelete=ForeignKeyAction.NoAction)
422        /** Foreign key referencing Genre (database name FK_TrackGenreId) */
423        lazy val genreFk = foreignKey("FK_TrackGenreId", genreid, Genre)(r=> r.genreid, onUpdate=ForeignKeyAction.NoAction, onDelete=ForeignKeyAction.NoAction)
424        /** Foreign key referencing Mediatype (database name FK_TrackMediaTypeId) */
425        lazy val mediatypeFk = foreignKey("FK_TrackMediaTypeId", mediatypeid, Mediatype)(r => r.mediatypeid, onUpdate=ForeignKeyAction.NoAction, onDelete=ForeignKeyAction.NoAction)
426      }
427      /** Collection-like TableQuery object for table Track */
428      lazy val Track = new TableQuery(tag => new Track(tag))
429    }

 

原文:http://www.scala-china.net/discuz/forum.php?mod=viewthread&tid=151252&extra=page%3D1