ActiveRecordÊÇRuby
on RailsµÄORM²ã£¬´óÌåÉÏÀàËÆÓÚJavaÖеÄHibernate¡£ActiveRecord»ùÓÚÔ¼¶¨ÓÅÓÚÅäÖõÄÔÔò£¬ËùÒÔËüʹÓÃÆðÀ´±ÈHibernate¸üÈÝÒס£ÔÚ¼ò»¯»ù±¾µÄÊý¾Ý²Ù×÷·½Ã棬Èç´´½¨¡¢¶ÁÈ¡¡¢¸üкÍɾ³ý£¬ËüȷʵÊǷdz£°ôµÄ¡£
½èÖúÓÚActiveRecord£¬ÄãµÄÄ£ÐÍÀàÒ²»á×÷ΪÊý¾Ý·ÃÎʶÔÏó£¨Data
Access Object£¬DAO£©À´Ö´ÐÐCRUD²Ù×÷¡£ÔÚ³õ²½Ì½¾¿Ö®ºó£¬ÎÒ¶ÔActiveRecord²úÉúÁËŨºñµÄÐËȤ£¬Òò´Ë¿ªÊ¼Ñ°ÕÒÒ»ÖÖ½â¾ö·½°¸À´¼ò»¯»ùÓÚJava³Ö¾Ã»¯API£¨Java
Persistence API£¬JPA£©µÄORM¿ò¼ÜµÄʹÓá£
´ó¶àÊýJPAÓ¦Óö¼»áÓÐijÖÖÀàÐ͵ÄÊý¾Ý·ÃÎʲ㣨Data Access Layer£¬DAL£©À´ÓëÊý¾Ý¿â½øÐн»»¥¡£Í¨³£DAL»á°üº¬Êý¾Ý·ÃÎʶÔÏó»ò·ûºÏRepositoryÉè¼ÆÄ£Ê½µÄÀà¡£
DAOµÄʵÏÖÓëʵÌå¶ÔÏóͨ³£ÊÇÒ»¶ÔÒ»µÄ¹ØÏµ£¬¶øRepositoryÔòÊÇÕë¶Ôÿ¸ö¾ÛºÏ¸ù£¨aggregate
root£©ÊµÏÖÒ»¸ö¡£²»¹ÜÊÇÄÄÖÖ³¡¾°£¬Ó¦ÓÃ×îºó¶¼»á´´½¨¶à¸öÀàÓëÊý¾Ý¿â½øÐн»»¥¡£¾¡¹ÜÊʵ±µÄ³éÏóÄܹ»ÓÐЧÏÞÖÆËù´´½¨ÀàµÄÊýÁ¿£¬µ«ÊÇËüÖÕ¾¿»¹ÊÇ»áÔÚÓ¦ÓÃÖÐÒýÈëÒ»¸ö¶îÍâµÄ²ã£¬Õâ¶¼ÊÇÐèҪά»¤ºÍ²âÊԵġ£
ActiveJPA»ùÓÚJPA£¬ÌṩÁËMartin FowlerËùÌá³öµÄ»î¶¯¼Ç¼ģʽ£¨Active
Record pattern£©µÄJavaʵÏÖ¡£½èÖúÓÚActiveJPA£¬Ä£Ðͱ¾Éí»á×÷ΪDAO²¢ÓëÊý¾Ý¿â½»»¥£¬ÕâÑù¾Í²»ÐèÒª¶îÍâµÄ´úÂë×÷ΪÊý¾Ý·ÃÎʲãÁË¡£
ActiveJPAʹÓõ½ÁËJPA¹æ·¶£¬Òò´ËËùÓÐJPAµÄORMʵÏÖ£¨Hibernate¡¢EclipseLink¡¢OpenJPAµÈ£©¶¼¿ÉÒÔÓëActiveJPAÐͬʹÓá£
½«ÒÑÓеÄJPAÄ£ÐÍת»»ÎªActiveJPA
Òª½«ÒÑÓеÄÄ£ÐÍת»»ÎªActiveJPA£¬Ö»ÐèÈÃÄãµÄÄ£ÐÍʵÏÖÀ©Õ¹org.activejpa.entity.
Model¼´¿É£º
@java.persistence.Entity public class YourModel extends org.activejpa.entity.Model { } |
Ö´ÐÐCRUD²Ù×÷
ÄãµÄÄ£Ðͽ«»á´ÓActiveJPAµÄÄ£ÐÍÀàÖм̳еõ½ºÜ¶àµÄCRUD¹¦ÄÜ¡£
//¸ù¾Ýid»ñµÃ¶©µ¥ Order order = Order.findById(12345L);
// ¸ù¾Ýcustomer»ñµÃÆäÒÑ·¢»õµÄ¶©µ¥
List orders = Order.where("customerEmail",
"dummyemail@dummy.com",
"status", "shipped");
// µÃµ½Æ¥Åä¹ýÂËÌõ¼þµÄµÚÒ»Ìõ¶©µ¥¼Ç¼
Long count = Order.first("customerEmail",
"dummyemail@dummy.com",
"status", "shipped");
// µÃµ½Æ¥Åä¹ýÂËÌõ¼þµÄΨһһÌõ¶©µ¥¼Ç¼
Long count = Order.one("customerEmail",
"dummyemail@dummy.com",
"status", "shipped");
// µÃµ½ËùÓеļǼ
List orders = Order.all();
// ¼ì²éÖ¸¶¨±êʶ·ûµÄ¶©µ¥ÊÇ·ñ´æÔÚ
boolean exists = Order.exists(1234L);
// ±£´æ¶©µ¥
order.persist();
// ɾ³ý¶©µ¥
order.delete();
// ˢж©µ¥
order.refresh();
// Óë³Ö¾Ã»¯ÉÏÏÂÎÄÖÐÒÑÓеĶ©µ¥½øÐкϲ¢
order.merge(); |
¹ýÂËÓë·ÖÒ³
¶Ô¼Ç¼½øÐйýÂËʱ£¬Äã²¢²»ÐèÒª´´½¨JPQL»òcriteria²éѯ¡£ActiveJPAÌṩÁËÒ»¸ö¸´ÔӵĹýÂËÆ÷£¬ÓÃÓÚÔÚ²»Í¬µÄ²Ù×÷¼ä½øÐÐÁ¬½Ó£¨conjunction£©£º
// »ñȡƥÅäÖ¸¶¨EmailµØÖ·ÇÒÕ˵¥¶î´óÓÚ1000µÄËùÓж©µ¥£¬²¢ÇÒÒª½øÐзÖÒ³ Filter filter = new Filter(); filter.setPageNo(1); filter.setPerPage(25); filter.addCondition(new Condition("customerEmail", Operator.eq, "dummyemail@dummy.com");
filter.addCondition(new Condition("billingAmount",
Operator.gt,
1000.00);
List orders = Order.where(filter);
// ¶ÔÂú×ã¹ýÂËÌõ¼þµÄ¶©µ¥½øÐмÆÊý
Long count = Order.count(filter);
// ɾ³ýÆ¥ÅäÕâ¸ö¹ýÂËÆ÷µÄ¶©µ¥
Long count = Order.deleteAll(filter); |
ǶÌײéѯ
ActiveJPAÔÊÐíǶÌ×¹ýÂ˲ÎÊý¡£ÕâÑùµÄ»°¾ÍÄܸüÈÝÒ×µØÔÚÔËÐÐʱ´´½¨¶¯Ì¬²éѯ¡£ÀýÈ磬Äã»ñÈ¡µÄ¶©µ¥ÖУ¬ÖÁÉÙÒªÓÐÒ»¸ö¶©µ¥ÏîÊÇ»ùÓÚ¡°book¡±Àà±ðµÄ²úÆ·´´½¨µÄ¡£
// µÃµ½ÖÁÉÙ°üº¬Ò»¸öbookÏîµÄËùÓж©µ¥ Filter filter = new Filter(); filter.setPageNo(1); filter.setPerPage(25); filter.addCondition(new Condition("orderItems.product.category", Operator.eq, "books"); List orders = Order.where(filter); |
ʹÓü¯ºÏ
ÉÏÃæÌÖÂÛµÄËùÓÐCRUD²Ù×÷ͬʱ¿ÉÒÔÔÚ¼¯ºÏ¼¶±ðÖ´ÐС£½«²éѯ·¶Î§ÉèÖõ½¼¯ºÏÀàµÄÓ÷¨ÈçÏÂËùʾ£º
// ÔÚ¶©µ¥ÖУ¬¸ù¾Ýid²éÕÒ¶©µ¥Ïî order.collections("orderItems").findById(123L);
// µÃµ½µÚÒ»¸öÒÑ·¢»õµÄ¶©µ¥Ïî
order.collections(¡°orderItems¡±).first(¡°status¡±,
¡°shipped¡±);
// µÃµ½ËùÓÐÈ¡ÏûµÄ¶©µ¥Ïî
order.collections(¡°orderItems¡±).where(¡°status¡±,
¡°cancelled¡±);
// µÃµ½¼¯ºÏÖеÄËùÓÐÏî
order.collections(¡°orderItems¡±).all();
// Íù¼¯ºÏÖÐÌí¼ÓÒ»Ïî
order.collections(¡°orderItems¡±).add(orderItem);
// ÒÆ³ý¼¯ºÏÖеÄÒ»Ïî
order.collections(¡°orderItems¡±).remove(orderItem); |
¹ýÂ˺ͷÖÒ³Ò²¿ÉÒÔʹÓõ½¼¯ºÏÖ®ÖÐ
// ¶ÔÒ»¸ö¶©µ¥ÖеĶ©µ¥Ïî»ùÓÚ¹ýÂËÆ÷½øÐвéѯ²¢½øÐзÖÒ³ Filter filter = new Filter(); filter.setPageNo(1); filter.setPerPage(25);
filter.addCondition(new Condition(¡°status¡±, ¡°shipped¡±);
order.collections("orderItems").where(filter);
// ÔÚ¶©µ¥ÖУ¬µÃµ½Æ¥Åä¹ýÂËÆ÷µÄ¶©µ¥ÏîµÄÊýÁ¿
order.collections(¡°orderItems¡±).count(filter); |
¶¯Ì¬¸üÐÂ
ActiveJPAÖ§³Ö¶ÔÄ£Ð͵Ķ¯Ì¬¸üС£ÔÚÓÐЩ³¡¾°ÏÂÕâÊǺÜÓÐÓõģ¬ÀýÈçÓû§Í¨¹ýä¯ÀÀÆ÷¸üÐÂÒ»¸ö±íµ¥¡£Äã¿ÉÒÔ´«µÝÒ»¸ö°üº¬ÊôÐÔµÄmapÀ´½øÐиüУ¬¶ø²»Êǵ÷ÓÃÿ¸öÊôÐÔµÄsetter·½·¨£º
// ¸üÐÂÊôÐÔ
Map attributes = new HashMap();
attributes.put("billingAmount", 1000.0);
order.updateAttributes(attributes); |
ÄãÒ²¿ÉÒÔ¸üзÇÔʼ/·Ç°ü×°ÀàÐ͵ÄÓò£¬Ö»Ðè¸øÕâЩ¶ÔÏó´«µÝmap¼´¿É¡£ÒÔϵÄÑùÀýÕ¹ÏÖÁ˸üÐÂÒ»¸ö¶©µ¥µÄÊÕ»ñµØÖ·ºÍÕ˵¥½ð¶î¡£
// ¸üÐÂÒ»¸ö¶©µ¥µÄÊÕ»ñµØÖ·ºÍÕ˵¥½ð¶î
Map attributes = new HashMap();
Map address = new HashMap();
address.put(¡°city¡±, ¡°Bangalore¡±);
address.put(¡°state¡±, ¡°Karnataka¡±);
attributes.put(¡°shippingAddress¡±, address);
attributes.put("billingAmount", 1000.0);
order.updateAttributes(attributes); |
×¢Ò⣺ĿǰÉв»Ö§³Ö¸üÐÂlist/set/arrayÓò£¬Î´À´µÄ°æ±¾½«»áÌṩ֧³Ö¡£
ÊÂÎñ´¦Àí
ĬÈÏÇé¿öÏ£¬Èç¹ûûÓÐÊÂÎñ£¬ActiveJPA½«»áΪËùÓеĸüвÙ×÷Æô¶¯Ò»¸öÊÂÎñ£¬²»¹ýÄãÒ²¿ÉÒÔ½«Õû¸ö¹¤×÷µ¥Ôª°ü×°µ½Ò»¸öÊÂÎñÖ®ÖУº
JPAContext context = JPA.instance.getDefaultConfig().getContext(); context.beginTxn(); boolean failed = true; try { // ÄãµÄ¹¤×÷µ¥ÔªÖÃÓÚ´Ë´¦ failed = false; } finally { // Ìá½»»ò»Ø¹öÊÂÎñ context.closeTxn(failed); } |
Èç¹ûÒѾ´æÔÚÁËÍⲿµÄÊÂÎñ£¬ÄÇôActiveJPA½«»áʹÓÃÕâ¸öÊÂÎñ£¬µ«ÊDz»»á½øÐÐÌá½»»ò»Ø¹ö¡£Ó¦¸ÃÓÉÓ¦ÓÃÀ´¸ºÔð¹Ø±Õ¸ÃÊÂÎñ¡£
²âÊÔÄãµÄÄ£ÐÍ
ActiveJPAΪTestNGÌṩÁËÒ»¸ö»ù±¾µÄ²âÊÔÀ࣬Ëü»á½«ActiveJPAÒÔ¹Ò¹³£¨hook£©µÄ·½Ê½Ìí¼Óµ½²âÊÔÔËÐÐʱ֮ÖС£Ö»ÐèÈÃÄãµÄ²âÊÔÀàÀ©Õ¹×Ôorg.activejpa.entity.testng.BaseModelTestÀ༴¿É¡£ÒÔÏÂΪһ¸öÑùÀý´úÂ룺
public class OrderTest extends BaseModelTest { @Test public void testCreateOrder() { Order order = new Order(); order.setCustomerEmail("dummyemail@dummy.com"); ... ... order.persist(); Assert.assertEquals(Order.where("customerEmail", "dummyemail@dummy.com").get(0), order); } } } |
ʹÓÃÆð²½
´î½¨Maven
ActiveJPA¿ÉÒÔÒÔMaven artifactµÄ·½Ê½À´»ñÈ¡£¬Äܹ»·Ç³£ÈÝÒ׵ؼ¯³Éµ½ÄãµÄÓ¦ÓÃÖ®ÖС£Ö»ÐèÔÚÄãµÄpom.xmlÎļþÖÐÌí¼ÓÈçϵÄmavenÒÀÀµ£º
<dependencies> <dependency> <groupId>org.activejpa</groupId> <artifactId>activejpa-core</artifactId> <version>0.1.5</version> </dependency> </dependencies>
<repositories>
<repository>
<id>activejpa-repo</id>
<url>https://raw.github.com/ActiveJpa/activejpa/mvn-repo/releases</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
</snapshots>
</repository>
</repositories> |
ǶÈëµ½ÄãµÄÓ¦ÓÃÖ®ÖÐ
ActiveJPAÐèÒªÔÚʵÌåÀà¼ÓÔØÇ°¾ÍǶÈëµ½ÄãµÄÓ¦ÓÃÖ®ÖС£Èç¹ûÄãʹÓÃTomcatµÄ»°£¬ÄÇôServletContextListener¾ÍÊÇ×öÕâ¼þʵÄÒ»¸öºÜºÃµÄµØ·½¡£Äã¿ÉÒÔ½«ÒÔϵĴúÂë±àдµ½ÉÏÏÂÎļàÌýÆ÷µÄcontextInitialized()·½·¨Ö®ÖС£
// ¶¯Ì¬¼ÓÔØJava´úÀí ActiveJpaAgentLoader.instance().loadAgent();
// Ìí¼Ó¶¨ÒåÔÚpersistence.xmlÖеij־û¯µ¥Ôª£¬ÒÔ¡°order¡±Ãû½øÐбêʶ¡£
persistence.xmlÓ¦¸ÃλÓÚÀà·¾¶ÏÂ
JPA.addPersistenceUnit("order");
// Èç¹ûÄãÒѾ´´½¨ÁËʵÌå¹ÜÀí¹¤³§µÄ»°£¬¿ÉÒÔ½«Æä¹ØÁªµ½ActiveJpaÉÏ
// JPA.addPersistenceUnit("order", entityManagerFactory); |
ÓëSpring¿ò¼Ü¼¯³É
½«ActiveJPAÓëSpringÕâÑùµÄ¿ò¼Ü½øÐм¯³ÉÊǺÜÈÝÒ׵ġ£´ó¶àÊýµÄÓ¦Óö¼»áʹÓÃSpringµÄ×¢½âÀ´ÅäÖÃJPAºÍ¹ÜÀíÊÂÎñ¡£ActiveJPAÄܹ»ÒÔÁ½ÖÖ·½Ê½À´½øÐÐÅäÖ᪡ªÄã¿ÉÒÔÈÃËüÀ´´´½¨ÊµÌå¹ÜÀí¹¤³§Ò²¿ÉÒÔ´«ÈëÒ»¸öÒÑ´æÔڵĶÔÏó¡£ÔÚSpringÅäÖÃJPAµÄÇé¿öÏ£¬ÎÒÃÇ¿ÉÒÔʹÓÃSpringËù´´½¨µÄʵÌå¹ÜÀí¹¤³§¡£ÕâÑù¾ÍÄܱ£Ö¤ActiveJPAʹÓÃSpringËù´´½¨µÄÏàͬµÄÁ¬½ÓºÍÊÂÎñ£¬´Ó¶øÌṩÎÞ·ìµÄ¼¯³É¡£
ÒÔϵĴúÂëÕ¹ÏÖÁËÈçºÎ½«ActiveJPA¼¯³Éµ½SpringÓ¦ÓÃÖ®ÖУ¬Õâ¸öÓ¦ÓÃÊDz¿ÊðÔÚservletÈÝÆ÷ÀïÃæµÄ¡£ËüʹÓÃÁËÒ»¸ö×Ô¶¨ÒåµÄÉÏÏÂÎļÓÔØ¼àÌýÆ÷£¬´Ó¶ø½«ActiveJPAǶÈëµ½Ó¦ÓÃÖ®ÖС£ÐèҪעÒâµÄÊÇ£¬ÕâºÜÀàËÆÓëÉÏÃæµÄservletÑùÀý£¬Çø±ðÔÚÓÚÕâÀïʹÓÃÁËSpring¿ò¼ÜµÄContextLoaderListener£º
public class CustomContextListener extends ContextLoaderListener { @Override public void contextInitialized(ServletContextEvent event) { try { // ÔÚÕâÀﶯ̬¼ÓÔØJava´úÀí ActiveJpaAgentLoader.instance().loadAgent(); } catch (Exception e) { throw new RuntimeException(e); } super.contextInitialized(event); JPA.instance.addPersistenceUnit("default", getCurrentWebApplicationContext().getBean(EntityManagerFactory. class), true); } } |
ÑùÀýÓ¦ÓÃ
ÔÚGitHubµÄActiveJPA¹¤³ÌÒ³ÃæÉÏÓÐÒ»¸öʾÀýÓ¦Ó㬰üº¬Á˺ܶà¸ü¾ßÌåµÄÑùÀý£¬Õ¹ÏÖÁËSpring-ActiveJPAµÄ¼¯³É¡£ |