尝试对具有关系的实体执行软删除会导致异常



最近,我对应用程序中的大多数实体(至少是我需要的实体)实现了软删除。实现如下所示:

目标.groovy

class Goal {
   String definition;
   Account account;
   boolean tmpl = false;
   String tmplName;
   Goal template
   Timestamp dateCreated
   Timestamp lastUpdated
   Timestamp deletedAt
   static belongsTo = [
      account: Account,
      template: Goal
   ]
   static hasMany = [perceptions: Perception, sessions: RankingSession]
   static mapping = {
      autoTimestamp true
      table 'goal'
      definition type: 'text'
      tmplName column: '`tmpl_name`'
      perceptions sort:'title', order:'asc'
      dateCreated column: 'date_created'
      lastUpdated column: 'last_updated'
      deletedAt column: 'deleted_at'
   }
   ...
   def beforeDelete() {
      if (deletedAt == null) {
         Goal.executeUpdate('update Goal set deletedAt = ? where id = ?', [new Timestamp(System.currentTimeMillis()), id])
      }
      return false
   }
   ...

Perception.groovy

class Perception {
   String title
   String definition
   Goal goal
   Timestamp dateCreated
   Timestamp lastUpdated
   Timestamp deletedAt
   static hasMany = [left: Rank, right: Rank]
   static mappedBy = [left: "left", right: "right"]
   static belongsTo = [goal: Goal]
   static namedQueries = {
      notDeleted {
         isNull 'deletedAt'
      }
   }
   static mapping = {
      autoTimestamp true
      table 'perception'
      definition type: 'text'
      dateCreated column: 'date_created'
      lastUpdated column: 'last_updated'
      deletedAt column: 'deleted_at'
   }
   static constraints = {
      title blank: false, size: 1..255
      definition nullable: true, blank: true, size: 1..5000
      goal nullable: false
      lastUpdated nullable: true
      deletedAt nullable: true
   }
   /**
    * before delete callback to prevent physical deletion
    *
    * @return
    */
   def beforeDelete() {
      if (deletedAt == null) {
         Perception.executeUpdate('update Perception set deletedAt = ? where id = ?', [new Timestamp(System.currentTimeMillis()), id])
      }
      return false
   }
}

Rank.groovy

class Rank {
   Perception left
   Perception right
   Integer leftRank
   Integer rightRank
   RankingSession session
   static belongsTo = [session: RankingSession]
   static mapping = {
      table 'rank'
   }
   static constraints = {
      leftRank range: 0..1, nullable: true 
      rightRank range: 0..1, nullable: true
      left nullable: false
      right nullable: false
      session nullable: false
   }
}

我的问题发生在删除(逻辑删除)。我通过以下方式通过服务类执行删除:

GoalService.groovy

@Transactional
class GoalService {
   /**
    * Deletes goal 
    * 
    * @param goal
    * @return
    */
   def deleteGoal(Goal goal) {
      if (goal.tmpl == true) {
         throw new ValidationException("Provided object is a template!")
      }
      def perceptions = Perception.notDeleted.findAllByGoal(goal)
      for (perception in perceptions) {
         perception.delete()
      }
      goal.delete()
   }
}

我有一个用例,它在一种条件下工作,在另一种情况下处理异常。

#1现有目标及其分配的感知数量。删除操作如预期:目标和感知标记为已删除。

#2有感知的目标+链接到感知的等级对象数。当我试图删除这样一个目标时,我得到了一个例外:

    Error 2015-03-23 14:52:10,294 [http-nio-8080-exec-9] ERROR spi.SqlExceptionHelper  - Column 'left_id' cannot be null
| Error 2015-03-23 14:52:10,357 [http-nio-8080-exec-9] ERROR errors.GrailsExceptionResolver  - MySQLIntegrityConstraintViolationException occurred when processing request: [POST] /triz/rrm/goal/1/delete - parameters:
SYNCHRONIZER_TOKEN: 57fda8f2-8025-45e0-ac60-592234f54ef1
SYNCHRONIZER_URI: /triz/rrm/goals
Column 'left_id' cannot be null. Stacktrace follows:
Message: Column 'left_id' cannot be null
    Line | Method
->>  411 | handleNewInstance  in com.mysql.jdbc.Util
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|    386 | getInstance        in     ''
|   1041 | createSQLException in com.mysql.jdbc.SQLError
|   4237 | checkErrorPacket   in com.mysql.jdbc.MysqlIO
|   4169 | checkErrorPacket . in     ''
|   2617 | sendCommand        in     ''
|   2778 | sqlQueryDirect . . in     ''
|   2834 | execSQL            in com.mysql.jdbc.ConnectionImpl
|   2156 | executeInternal .  in com.mysql.jdbc.PreparedStatement
|   2441 | executeUpdate      in     ''
|   2366 | executeUpdate . .  in     ''
|   2350 | executeUpdate      in     ''
|    129 | doCall . . . . . . in triz.rrm.RrmGoalController$_delete_closure5
|    127 | delete             in triz.rrm.RrmGoalController

我已经试过了所有的东西,包括:

  • 物理删除了所有约束
  • 在关系上使用了"cascade:保存更新"

没有什么帮助,我唯一能理解的是它与级联有关,但如果事实上我正在更新对象,为什么GORM要尝试级联"删除"?

由于Rank有对Perception的引用,但您没有在任何一侧指定belongsTo,因此您得到了异常。

你在Rank:中有这个

Perception left

这就是为什么你得到Column 'left_id' cannot be null. Stacktrace follows...

因此,要解决此问题,请删除每个要删除的perception都具有r/ship的rank对象,或者在Rank中指定belongsTo = [left: Perception]

最新更新