Justin on February 16th, 2011

The Problem

You’ve set up a .Net project using Oracle with NHibernate.  Your Id fields are auto-incremented in Oracle using triggers and sequence numbers. You’ve created your objects and mapping files, and things seem to mostly work, but you notice some strange things. For one, there are lots of holes in your Id numbers. For another, when you save a new object that has a child collection of objects, you notice that the foreign key Id number in the parent and children are off by one. You could resort to a work-around of saving the child objects independently, but that is a major inconvenience.

Underneath the Hood

What is probably happening is that NHibernate is accessing your Oracle sequence number more than once, causing it to increment each time you access it. If you look at your mapping files, you probably have your Id fields set up like this:

<id name="Id" column="APS_JOB_SEQ" type="Int32" unsaved-value="0">
    <generator class="native">
        <param name="sequence">SQ_APS_JOB_SEQ</param>
    </generator>
</id>

A Simple Solution

By making a simple change in an attribute of your <generator> tag, you can probably make your Id problems go away:

<id name="Id" column="APS_JOB_SEQ" type="Int32" unsaved-value="0">
  <generator class="trigger-identity">
      <param name="sequence">SQ_APS_JOB_SEQ</param>
  </generator>
</id>

By setting the generator class attribute to "trigger-identity", you prevent NHibernate from making separate calls to the sequence.

Justin on February 5th, 2011

Coalescing undo, otherwise known as chunked undo, is handy for undoing a whole group of changes when the user selects Edit->Undo (or Command-Z). I recently encountered a scenario for which coalescing undo was required.

My application has a custom view containing text boxes that the user can edit and drag around the view. When I implemented Undo for these action, I noticed that, after dragging a text box, the Undo action would only move the text box back a couple of pixels, and then a couple more pixels when I selected Undo again, and so on, and so on. In other words, each mouseDragged event caused the text box bounds to be updated, which in turn caused another NSInvocation to be pushed onto the Undo stack.

The behavior that I wanted was for the text box to go all the way back to its original position when the user selected Undo. My first attempt involved turning on the coalescing undo on the mouseDown event and turning it off on the mouseUp event. This worked, but it had the undesired side effect of placing a new item on the Undo stack even when no dragging took place, i.e., the user could simply click on a text box, and there would be an Undo item for that click. I wanted the grouping to only have an effect on dragging.

Here is how I got it to work without an awful lot of code. If you have a better way, please leave a comment!

For the mouseDown event, you invoke the undoManager and specify that the grouping, or coalescing, should begin:

1
2
3
4
5
6
- (void)mouseDown:(NSEvent *)event {
	NSUndoManager *undoManager = [document undoManager];
	[undoManager beginUndoGrouping];
 
	// your mouseDown code here...
}

For the mouseDragged event, you simply set a class variable indicating that a drag is taking place:

1
2
3
4
5
6
- (void)mouseDragged:(NSEvent *)theEvent
{
	isDragging = YES;
 
	// your dragging code here...
}

Finally, the mouseUp event does most of the work, which is explained below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (void)mouseUp:(NSEvent *)theEvent
{
	NSUndoManager *undoManager = [document undoManager];
	[undoManager endUndoGrouping];
 
	if (isDragging) {
		NSRect newBounds = [selectedTextbox bounds];
		[undoManager disableUndoRegistration];
		[undoManager undoNestedGroup];
		[undoManager enableUndoRegistration];
		[selectedTextbox setBounds:newBounds];
	}
	isDragging = NO;
}

When the mouseUp event fires, you know that the dragging has ended, so you end the grouping by calling [undoManager endUndoGrouping].

If you are just finishing a drag (isDragging set to YES), then record the new bounds of the text box (selectedTextbox, in this example) into an NSRect (newBounds, in this example).

Temporarily disable the Undo mechanism by calling [undoManager disableUndoRegistration]. Pop the group off of the Undo stack by calling [undoManager endNestedGrouping]. Turn the Undo mechanism back on by calling [undoManager enableUndoRegistration].

At this point, things are reset like they were before the drag began, so you need to set the bounds of the text box to the new bounds you saved a little earlier by calling [selectedTextbox setBounds:newBounds].

Not the perfect solution, I’m sure, but it works!

Tags: , , , ,

Justin on January 28th, 2011

I’ve just installed WordPress to get this blog underway, and since I will be dealing with software development topics, I needed a code syntax highlighter. I found a good one named WP-Syntax.

Here’s a code snippet in Objective-C:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- (void)createDisplayImage
{
	if (displayImage != nil) {
		[displayImage release];
		displayImage = nil;
	}
	displayImage = [[NSImage alloc] initWithSize:NSMakeSize(IMAGE_DIMENSION, IMAGE_DIMENSION)];
	[displayImage lockFocus];
	NSImage *img = [document image];
	if (img != nil) {
		[img drawInRect:NSMakeRect(0.0, 0.0, IMAGE_DIMENSION, IMAGE_DIMENSION)
			fromRect:[self scaledRectOfCroppedSource]
			  operation:NSCompositeCopy fraction:1.0];
	} else {
		[[NSColor whiteColor] set];
		NSRectFill(NSMakeRect(0.0, 0.0, IMAGE_DIMENSION, IMAGE_DIMENSION));
	}
 
	[displayImage unlockFocus];
}

To get this to work, all you have to do is switch to HTML mode when writing your post, then use the PRE tag like this:

<pre lang=”objc” line=”1″>your source code…</pre>

Not too difficult, eh?

One thing I noticed, however, is that when I switched to Visual mode and then back to HTML, the “line” attribute got stripped from the PRE tag. Something to keep in mind.