public function save(ModelInterface $item, $timestamp = 0, $recursive = false)
    {
        if (!\is_int($timestamp)) {
            throw new DcGeneralException('The parameter for this method has been change!');
        }
        $data = $item->getProperty('rows');
        if (!($data && $item->getId())) {
            throw new DcGeneralException('invalid input data in model.', 1);
        }

        $keep = [];
        foreach ($data as $row) {
            $sqlData = $row;

            // Update all.
            $intId = (int) $row['id'];

            // Always unset id.
            unset($sqlData['id']);

            // Work around the fact that multicolumnwizard does not clear any hidden fields when copying a dataset.
            // therefore we do consider any dupe as new dataset and save it accordingly.
            if (\in_array($intId, $keep)) {
                $intId = 0;
            }

            if ($intId > 0) {
                $this->connection->update(
                    $this->source,
                    $sqlData,
                    ['id' => $intId, $this->strGroupCol => $item->getId()]
                );
                $keep[] = $intId;

                continue;
            }

            // Force group col value.
            $sqlData[$this->strGroupCol] = $item->getId();

            $this->connection->insert($this->source, $sqlData);

            $keep[] = $this->connection->lastInsertId($this->source);
        }

        // House keeping, kill the rest.
        $queryBuilder = $this->connection->createQueryBuilder();
        $queryBuilder->delete($this->source);
        $queryBuilder->andWhere($queryBuilder->expr()->eq($this->strGroupCol, ':' . $this->strGroupCol));
        $queryBuilder->setParameter(':' . $this->strGroupCol, $item->getId());
        $queryBuilder->andWhere($queryBuilder->expr()->notIn('id', $keep));

        $queryBuilder->execute();

        return $item;
    }