      ;; neither exists: autogenerate
      (and (nil? key-property-value) (nil? metadata-key-value))
      nil
+     ;; metadata key exists
+     (and (not (nil? metadata-key-value)) (instance? Key metadata-key-value))
+     metadata-key-value
      ;; key property exists
      (not (nil? key-property-value))
      (if parent
          (KeyFactory/createKey (get-key-object parent) datastore-entity-name key-property-value)
          (KeyFactory/createKey datastore-entity-name key-property-value))
-     ;; metadata key exists
-     (and (not (nil? metadata-key-value)) (instance? Key metadata-key-value))
-     metadata-key-value
      ;; something's wrong
      :else (throw (RuntimeException.
                    "entity has no valid :key metadata, and has no fields marked :key")))))

            Entity]))


(defonce *default-datastore-service* (atom nil))


(defn- get-datastore-service [& {:keys [service]}]
  (if (nil? service)
      (do (when (nil? @*default-datastore-service*)
            (reset! *default-datastore-service* (DatastoreServiceFactory/getDatastoreService)))
          @*default-datastore-service*)
      service))


(defn- unqualified-name [sym]

         (save!-helper this# ~datastore-entity-name))
       (save! [this# parent#]
         (save!-helper this# ~datastore-entity-name :parent parent#)))))


;;; Note that the code relies on the API's implicit transaction tracking, and
;;; the *current-transaction* value is not used. Making it available just in
;;; case.
(defmacro with-transaction [& body]
  `(binding [*current-transaction* (.beginTransaction (get-datastore-service))]
     (try
       (let [body-result# ~@body]
         (.commit *current-transaction*)
         body-result#)
       (catch Throwable err#
         (do (.rollback *current-transaction*)
             (throw err#))))))
