org.seasar.doma.jdbc.JdbcException: [DOMA2022] IDプロパティのないエンティティ[LogicalDeletable]の更新や削除はできません
Last active
December 10, 2015 03:08
-
-
Save gakuzzzz/4372720 to your computer and use it in GitHub Desktop.
汎用的なDelegateのリフレクション使わない版
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.joda.time.DateTime; | |
import org.seasar.doma.Column; | |
import org.seasar.doma.Entity; | |
@Entity | |
public abstract class LogicalDeletable { | |
@Column | |
protected DateTime deletedTime; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import javax.annotation.Nonnull; | |
import org.seasar.doma.Column; | |
import org.seasar.doma.Entity; | |
import org.seasar.doma.GeneratedValue; | |
import org.seasar.doma.GenerationType; | |
import org.seasar.doma.Id; | |
import org.seasar.doma.SequenceGenerator; | |
import org.seasar.doma.jdbc.entity.NamingType; | |
@Entity(naming = NamingType.SNAKE_UPPER_CASE) | |
public class Employee extends LogicalDeletable { | |
@Id | |
// @GeneratedValue(strategy = GenerationType.SEQUENCE) // Domainオブジェクトに@GeneratedValueつけようとすると怒られる | |
// @SequenceGenerator(sequence = "EMPLOYEE_SEQ") | |
public EmployeeId id; | |
@Column | |
public String name; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.seasar.doma.Dao; | |
import org.seasar.doma.Delegate; | |
import org.seasar.doma.Update; | |
@Dao | |
public interface LogicalDeletableDao { | |
@Update | |
int update(LogicalDeletable entity); | |
@Delegate(to = LogicalDeletableDaoDelegate.class) | |
int delete(LogicalDeletable entity); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.joda.time.DateTime; | |
import org.seasar.doma.jdbc.Config; | |
public class LogicalDeletableDaoDelegate { | |
private final Config config; | |
private final LogicalDeletableDao dao; | |
public LogicalDeletableDaoDelegate(final Config config, final LogicalDeletableDao dao) { | |
this.config = config; | |
this.dao = dao; | |
} | |
public int delete(final LogicalDeletable entity) { | |
entity.deletedTime = DateTime.now(); | |
return dao.update(entity); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.seasar.doma.Dao; | |
import org.seasar.doma.Delegate; | |
import org.seasar.doma.Insert; | |
import org.seasar.doma.Select; | |
import org.seasar.doma.Update; | |
@Dao | |
public interface EmployeeDao extends LogicalDeletableDao { | |
@Update | |
int update(Employee entity); | |
@Insert | |
int insert(Employee entity); | |
@Delegate(to = LogicalDeletableDaoDelegate.class) | |
int delete(Employee entity); | |
} |
LogicalDeletableDao
を 以下のようにすればいけるかと思ったが、
@Dao
public interface LogicalDeletableDao<T extends LogicalDeletableEntity> {
@Update
int update(T entity);
@Delegate(to = LogicalDeletableDaoDelegate.class)
int delete(T entity);
}
[DOMA4059] Daoインタフェースには型パラメータを定義できません。
というエラーで怒られる。
かといって@Dao
を付けないと
[DOMA4188] @Daoが注釈されたインタフェースは@Daoが注釈されてないインタフェース[models.shared.LogicalDeletableDao]をextendsできません。
となる。
余談だが、Domain Object型のプロパティに @GeneratedValue
を付けようとすると怒られる。
@Id
に Domain Object型が使えなくて非常につらいです……。
了解です。
EntityListener周辺の機能拡張で進めます。
色々わがままを
こちらとしては、いろいろ意見を聞けておもしろいのでお気になさらず。
対応してみました。このSNAPSHOTでお試しください。
EntityListenerのcontextからメソッドやConfigを取れるようにしました。こんな感じで取得できます。
public class EmployeeListener implements EntityListener<Employee> {
@Override
public void preUpdate(Employee employee, PreUpdateContext context) {
// Daoのメソッドを取得
Method method = context.getMethod();
// Daoに指定したConfigを取得
Config config = context.getConfig();
...
}
...
}
それから、Entityクラスにて、@GeneratedValueや@Versionを注釈したプロパティをドメインクラスの型で定義できるようにしました。
先日行った、@DeleGateで互換性のあるDaoやEntityを受け入れる修正(https://gist.github.com/4355837) は一旦取り除いてあります。
ありがとうございます。早速試してみました。
一点はまりましたが、上手くいきました!!
ハマったのは以下のポイントです。
@Entity
public abstract class AbstractEntity {
@Column
public DateTime createdAt;
@Column
public DateTime updatedAt;
}
@Entity
public abstract class LogicalDeletable extends AbstractEntity {
@Column
protected DateTime deletedAt;
}
public class InitializeTimestampEntityListener implements EntityListener<AbstractEntity> {
@Override
public void preInsert(final AbstractEntity entity, final PreInsertContext context) {
entity.createdAt = DateTime.now();
entity.updatedAt = DateTime.now();
}
@Override
public void preUpdate(final AbstractEntity entity, final PreUpdateContext context) {
entity.updatedAt = DateTime.now();
}
...
}
public class LogicalDeletableEntityListener extends InitializeTimestampEntityListener {
@Override
public void preUpdate(final AbstractEntity entity, final PreUpdateContext context) {
super.preUpdate(entity, context);
if (context.getMethod().isAnnotationPresent(LogicalDeletion.class)) {
entity.deletedAt = DateTime.now(); // 型があわないので deletedAt にアクセスできない!
}
}
}
Entity の型があわずに deletedAt
にアクセスできない感じです。
以下のようにすると Java Compiler がエラー吐いて落ちます^^;;;
public class InitializeTimestampEntityListener<T extends AbstractEntity> implements EntityListener<T> {
...
}
public class LogicalDeletableEntityListener extends InitializeTimestampEntityListener<LogicalDeletable> {
...
}
一応、以下のようにすることで対応は可能でした。
public abstract class AbstractInitializeTimestampEntityListener<T extends AbstractEntity> implements EntityListener<T> {
@Override
public void preInsert(final T entity, final PreInsertContext context) {
entity.createdAt = DateTime.now();
entity.updatedAt = DateTime.now();
}
@Override
public void preUpdate(final T entity, final PreUpdateContext context) {
entity.updatedAt = DateTime.now();
}
}
public class InitializeTimestampEntityListener extends AbstractInitializeTimestampEntityListener<AbstractEntity> {}
public class LogicalDeletableEntityListener extends AbstractInitializeTimestampEntityListener<LogicalDeletableEntity> {
@Override
public void preUpdate(final LogicalDeletableEntity entity, final PreUpdateContext context) {
super.preUpdate(entity, context);
if (context.getMethod().isAnnotationPresent(LogicalDeletion.class)) {
entity.deletedAt = DateTime.now();
}
}
}
取り急ぎご報告まで
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
あれこれ考えてみましたが、ご提案頂いた
PreUpdateContext
がメソッドの情報を返してくれる形がやっぱり一番良さそうです。EntityListener
の継承に若干迷いがありましたが、よくよく考えるとそこまで強く否定する材料もなかったです。お手すきの際にでも
getDaoMethod()
の実装を入れて頂けますでしょうか?色々わがままを申してお手数をお掛けしますが、よろしくお願いしますm(_ _)m