UPDATE: Tôi tạo ra một dự án tập trung vào việc giải quyết vấn đề này được gọi là JIRM: https://github.com/agentgt/jirm
Tôi chỉ tìm thấy câu hỏi này sau khi thực hiện của riêng tôi sử dụng Spring JDBC và Jackson Object Mapper. Về cơ bản tôi chỉ cần một số tối thiểu SQL < -> ánh xạ đối tượng bất biến.
Nói tóm lại tôi chỉ sử dụng Springs RowMapper và Jackson's ObjectMapper để ánh xạ các đối tượng qua lại từ các cơ sở dữ liệu. Tôi sử dụng chú thích JPA chỉ dành cho siêu dữ liệu (như tên cột, v.v ...). Nếu mọi người quan tâm tôi sẽ làm sạch nó và đặt nó trên github (ngay bây giờ nó chỉ trong repo riêng của khởi động của tôi).
Dưới đây là một ý tưởng thô thế nào nó hoạt động ở đây là một đậu dụ (thông báo như thế nào tất cả các lĩnh vực là cuối cùng):
//skip imports for brevity
public class TestBean {
@Id
private final String stringProp;
private final long longProp;
@Column(name="timets")
private final Calendar timeTS;
@JsonCreator
public TestBean(
@JsonProperty("stringProp") String stringProp,
@JsonProperty("longProp") long longProp,
@JsonProperty("timeTS") Calendar timeTS) {
super();
this.stringProp = stringProp;
this.longProp = longProp;
this.timeTS = timeTS;
}
public String getStringProp() {
return stringProp;
}
public long getLongProp() {
return longProp;
}
public Calendar getTimeTS() {
return timeTS;
}
}
đây những gì RowMapper trông giống như (chú ý nó chủ yếu delegats để Springs ColumnMapRowMapper và sau đó sử dụng objectmapper Jackson):
public class SqlObjectRowMapper<T> implements RowMapper<T> {
private final SqlObjectDefinition<T> definition;
private final ColumnMapRowMapper mapRowMapper;
private final ObjectMapper objectMapper;
public SqlObjectRowMapper(SqlObjectDefinition<T> definition, ObjectMapper objectMapper) {
super();
this.definition = definition;
this.mapRowMapper = new SqlObjectMapRowMapper(definition);
this.objectMapper = objectMapper;
}
public SqlObjectRowMapper(Class<T> k) {
this(SqlObjectDefinition.fromClass(k), new ObjectMapper());
}
@Override
public T mapRow(ResultSet rs, int rowNum) throws SQLException {
Map<String, Object> m = mapRowMapper.mapRow(rs, rowNum);
return objectMapper.convertValue(m, definition.getObjectType());
}
}
Bây giờ tôi chỉ mất mùa xuân JdbcTemplate và cho nó một thạo wrapper. Dưới đây là một số ví dụ:
@Before
public void setUp() throws Exception {
dao = new SqlObjectDao<TestBean>(new JdbcTemplate(ds), TestBean.class);
}
@Test
public void testAll() throws Exception {
TestBean t = new TestBean(IdUtils.generateRandomUUIDString(), 2L, Calendar.getInstance());
dao.insert(t);
List<TestBean> list = dao.queryForListByFilter("stringProp", "hello");
List<TestBean> otherList = dao.select().where("stringProp", "hello").forList();
assertEquals(list, otherList);
long count = dao.select().forCount();
assertTrue(count > 0);
TestBean newT = new TestBean(t.getStringProp(), 50, Calendar.getInstance());
dao.update(newT);
TestBean reloaded = dao.reload(newT);
assertTrue(reloaded != newT);
assertTrue(reloaded.getStringProp().equals(newT.getStringProp()));
assertNotNull(list);
}
@Test
public void testAdding() throws Exception {
//This will do a UPDATE test_bean SET longProp = longProp + 100
int i = dao.update().add("longProp", 100).update();
assertTrue(i > 0);
}
@Test
public void testRowMapper() throws Exception {
List<Crap> craps = dao.query("select string_prop as name from test_bean limit ?", Crap.class, 2);
System.out.println(craps.get(0).getName());
craps = dao.query("select string_prop as name from test_bean limit ?")
.with(2)
.forList(Crap.class);
Crap c = dao.query("select string_prop as name from test_bean limit ?")
.with(1)
.forObject(Crap.class);
Optional<Crap> absent
= dao.query("select string_prop as name from test_bean where string_prop = ? limit ?")
.with("never")
.with(1)
.forOptional(Crap.class);
assertTrue(! absent.isPresent());
}
public static class Crap {
private final String name;
@JsonCreator
public Crap(@JsonProperty ("name") String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
}
Lưu ý ở trên mức độ dễ dàng để ánh xạ bất kỳ truy vấn nào vào POJO bất biến. Đó là bạn không cần nó 1-to-1 của thực thể để bàn. Cũng lưu ý việc sử dụng Guava's optionals (truy vấn cuối cùng .. cuộn xuống). Tôi thực sự ghét cách ORM ném ngoại lệ hoặc trả lại null
.
Hãy cho tôi biết nếu bạn thích nó và tôi sẽ dành thời gian cho nó trên github (chỉ teste với postgresql). Nếu không với thông tin ở trên, bạn có thể dễ dàng thực hiện của riêng bạn bằng cách sử dụng Spring JDBC. Tôi bắt đầu thực sự đào nó bởi vì những vật thể bất biến dễ hiểu và dễ hiểu hơn.
Theo tôi biết Hibernate không hỗ trợ các trường cuối cùng và "hàm tạo đầu phun" của các giá trị. –
bạn có cần 'final' không? Bạn chỉ có thể giới hạn nó với việc thiếu người định cư. – Bozho
Sẽ không thay đổi nếu không. Tôi không thích các khung công tác để hạn chế lựa chọn các tính năng ngôn ngữ của mình. –