You'd think I could read the only sticky post without getting linked to it!

Let's see if I can clearly explain my use cases. The simplest to
explain is that I'd like to use UUIDs as the primary key of a table.
To do this, I've done something like this:

class MappedStringPrimaryKey[T<:Mapper[T]] (
    override val fieldOwner: T, override val maxLen: Int)
      extends MappedStringIndex[T](fieldOwner, maxLen)
        with LifecycleCallbacks {
  override def writePermission_? = true
  override def dbDisplay_? = true
  override def dbAutogenerated_? = false

  override def fieldCreatorString(
      dbType: DriverType, colName: String): String =
        colName+" CHAR("+maxLen+") NOT NULL "
}

class UUIDPrimaryKey[T<:Mapper[T]] (
  override val fieldOwner: T) extends MappedStringPrimaryKey[T](
    fieldOwner, 16) {
  override def dbDisplay_? = false
  override def dbIndexFieldIndicatesSaved_? = (i_is_! != defaultValue)
  override lazy val defaultValue = {
    val uuid = UUID.randomUUID.toString.replaceAll("-", "").elements
    (new URLCodec).decode(uuid.zip(uuid).map(x=>"%"+x._1+x._2).mkString)
  }
}

The first problem is that while MappedStringIndex is setup as a
primary key, the field is required to be NOT NULL. Secondly, the
dbIndexFieldIndicatesSaved_? ends up being a little non-intuitive (I
would have expected it to be part of MappedStringIndex as well).

Also, with this use case, I had to make a couple modifications to
MetaMapper itself. The first one:

@@ -884,7 +891,7 @@ trait MetaMapper[A<:Mapper[A]] extends
BaseMetaMapper with Mapper[A] {
             mappedColumnInfo(colName) = mf
             mappedColumns(colName) = v
           }
-          if (mf.dbPrimaryKey_? && mf.dbAutogenerated_?) {
+          if (mf.dbPrimaryKey_?) {
             indexMap =
Full(MapperRules.quoteColumnName(mf.dbColumnName)) //
Full(v.getName.toLowerCase)
           }

Without indexMap being defined, if I do something along these lines:

Field.save
Field.save

(save twice in succession) I get a duplicate key value error because
the save call is trying to insert the object again.

The second modification that I made to MetaMapper:

@@ -600,10 +603,13 @@ trait MetaMapper[A<:Mapper[A]] extends
BaseMetaMapper with Mapper[A] {
           try {
             if (rs.next) {
               val meta = rs.getMetaData
-              toSave.runSafe {
-                findApplier(indexMap.open_!, rs.getObject(1)) match {
-                  case Full(ap) => ap.apply(toSave, rs.getObject(1))
-                  case _ =>
+              if (indexedField(toSave).map(_.dbAutogenerated_?)
+                  getOrElse false) {
+                toSave.runSafe {
+                  findApplier(indexMap.open_!, rs.getObject(1)) match {
+                    case Full(ap) => ap.apply(toSave, rs.getObject(1))
+                    case _ =>
+                  }
                 }
               }
               !rs.next

If I don't do this patch, when the object is saved, the value gets
reset from "foobar" to "1". The database stores it correctly, it's
simply the object that has its attributes wrong.

My other use case is documented below. I'm trying to set the value of
the primary key before submitting. At this point, i_is_! is always
different than the defaultValue and without using the afterSave hook,
the object tries to update instead of insert itself. While this isn't
a big issue, it just seems like there must be a better solution to the
problem.

Overall, if some general kind of solution for both of these problems
(updates to MappedStringIndex perhaps) made it in, I'd be ecstatic.

On Tue, Sep 22, 2009 at 8:36 AM, David Pollak
<feeder.of.the.be...@gmail.com> wrote:
> Thomas,
>
> We, as a rule, do not accept patches.  For a complete discussion, please
> see:
> http://groups.google.com/group/liftweb/browse_frm/thread/0c7a97cbf60780f0?hl=en#
>
> The current state of mapper's primary key support is sub-optimal.  There
> have been a couple of discussions of the issues on-list.  I am hoping to
> spend some time on this issue on Thursday.  If you've got specific
> requirements or specific tests, please post them.
>
> Thanks,
>
> David
>
> On Mon, Sep 21, 2009 at 9:33 PM, Thomas Rampelberg <pyronic...@gmail.com>
> wrote:
>>
>> I've been working at getting MetaMapper to work with primary keys that
>> aren't auto-generated (or longs). Towards this end, I've got a patch
>> for MetaMapper.scala that I'd like to get in. Who could I talk about
>> the process for that?
>>
>> In addition, as part of implementing the functionality, I ran into
>> some interesting problems. The most interesting one has to do with
>> dbIndexFieldIndicatesSaved_?. The default (i_is_! != defaultValue)
>> works great for cases where you're using the default value for the
>> actual primary key. Unfortunately, if you use something like this when
>> you're actively setting the primary key yourself there are some
>> unfortunate side effects (nothing gets saved to the database).
>>
>> To get around this, I'm doing something along these lines:
>>
>> class InfoHashPrimaryKey[T<:Mapper[T]] (
>>  override val fieldOwner: T) extends MappedStringPrimaryKey[T] (
>>    fieldOwner, 20) with LifecycleCallbacks {
>>    private var _saved = false
>>    override def dbIndexFieldIndicatesSaved_? = _saved
>>    override def afterSave = _saved = true
>>  }
>>
>> Would there happen to be a better way to do this? Leveraging an
>> afterSave hook seems like potential overkill.
>>
>>
>
>
>
> --
> Lift, the simply functional web framework http://liftweb.net
> Beginning Scala http://www.apress.com/book/view/1430219890
> Follow me: http://twitter.com/dpp
> Git some: http://github.com/dpp
>
> >
>

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to 
liftweb+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to