More Custom Settings Semantics (this time featuring Data Silo!)

1 Mar

In my continuing series on custom settings semantics, here’s a test class that shows what happens when you try to access existing custom settings in tests with SeeAllData set to true and false.

The org has 2 settings:

1. A list setting with a row called ‘foo’

2. A hierarchy setting with a row for the sysadmin user and a field called color__c (the user has it set to ‘blue’)

@istest public class DataSiloCSTest {
 @IsTest(SeeAllData=true) public static void 
    testAccessExisting() {
 privatecs__c x = privatecs__c.getInstance('foo');
 System.assert(x != null);
 System.assertEquals('foo', x.name);

 x = privatecs__c.getValues('foo');
 System.assert(x != null);
 System.assertEquals('foo', x.name);

 x = [select name from privatecs__c where 
    name='foo' limit 1];
 System.assert(x != null);
 System.assertEquals('foo', x.name);

 mycs__c a = mycs__c.getInstance(UserInfo.getUserId());
 System.assert(a != null);
 System.assertEquals('blue', a.color__c);

 a = mycs__c.getValues(UserInfo.getUserId());
 System.assert(a != null);
 System.assertEquals('blue', a.color__c);

 a = [select color__c from mycs__c where 
    setupownerid=:UserInfo.getUserId() limit 1];
 System.assert(a != null);
 System.assertEquals('blue', a.color__c);
 }

 @IsTest(SeeAllData=false) public static void 
    testNoAccessExisting() {
 privatecs__c x = privatecs__c.getInstance('foo');
 System.assert(x == null);

 x = privatecs__c.getValues('foo');
 System.assert(x == null);

 List<privatecs__c> y = [select name from privatecs__c 
    where name='foo'];
 System.assertEquals(0, y.size());

 mycs__c a = mycs__c.getInstance(UserInfo.getUserId());
 System.assert(a != null);
 System.assertEquals(null, a.color__c);

 a = mycs__c.getValues(UserInfo.getUserId());
 System.assert(a == null);

 List<mycs__c> b = [select color__c from mycs__c where 
    setupownerid=:UserInfo.getUserId() limit 1];
 System.assertEquals(0, b.size());
 }
}

More Custom Settings semantics (this time featuring Data Silo!)

1 Mar

In my continuing series on custom settings semantics, here’s a test class that shows what happens when you try to access existing custom settings in tests with SeeAllData set to true and false.

The org has 2 settings:

1. A list setting with a row called ‘foo’

2. A hierarchy setting with a row for the sysadmin user and a field called color__c (the user has it set to ‘blue’)

@istest public class DataSiloCSTest {
@IsTest(SeeAllData=true) public static void testAccessExisting() {
privatecs__c x = privatecs__c.getInstance('foo');
System.assert(x != null);
System.assertEquals('foo', x.name);

x = privatecs__c.getValues('foo');
System.assert(x != null);
System.assertEquals('foo', x.name);

x = [select name from privatecs__c where name='foo' limit 1];
System.assert(x != null);
System.assertEquals('foo', x.name);

mycs__c a = mycs__c.getInstance(UserInfo.getUserId());
System.assert(a != null);
System.assertEquals('blue', a.color__c);

a = mycs__c.getValues(UserInfo.getUserId());
System.assert(a != null);
System.assertEquals('blue', a.color__c);

a = [select color__c from mycs__c where setupownerid=:UserInfo.getUserId() limit 1];
System.assert(a != null);
System.assertEquals('blue', a.color__c);
}

@IsTest(SeeAllData=false) public static void testNoAccessExisting() {
privatecs__c x = privatecs__c.getInstance('foo');
System.assert(x == null);

x = privatecs__c.getValues('foo');
System.assert(x == null);

List<privatecs__c> y = [select name from privatecs__c where name='foo'];
System.assertEquals(0, y.size());

mycs__c a = mycs__c.getInstance(UserInfo.getUserId());
System.assert(a != null);
System.assertEquals(null, a.color__c);

a = mycs__c.getValues(UserInfo.getUserId());
System.assert(a == null);

List<mycs__c> b = [select color__c from mycs__c where setupownerid=:UserInfo.getUserId() limit 1];
System.assertEquals(0, b.size());
}
}

Hierarchy Custom Settings Semantics Explained

14 Feb

I get a lot of questions about exactly how getInstance(), getValues(), and getOrgDefaults() work in hierarchy Custom Settings, so I thought I’d lay it all out here.

A hierarchy custom setting can have values at 3 levels: User, Profile, and Organization. Under the hood, these are represented by 3 different rows, with different values for the SetupOwnerId column. For example, let’s say you have a setting called Car__c, with fields Make__c and Model__c, and your user’s IDs are:

org id: 00Dxxxxxxxxxxxx
profile id: 00exxxxxxxxxxxx
user id: 005xxxxxxxxxxxx

The table might look like this:

SetupOwnerId     Make__c  Model__c
<null>           Ford
00exxxxxxxxxxxx           Taurus
005xxxxxxxxxxxx  Toyota

Now, getValues() will always return the individual row:

getValues('00Dxxxxxxxxxxxx') ==>
  make=Ford, model=null, setupownerid=null
getValues('00exxxxxxxxxxxx') ==> 
  make=null, model=Taurus, setupownerid=00exxxxxxxxxxxx
getValues('005xxxxxxxxxxxx') ==> 
  make=Toyota, model=null, setupownerid=005xxxxxxxxxxxx

and getInstance()/getOrgDefaults() rolls up the rows:

getInstance('00Dxxxxxxxxxxxx')/getOrgDefaults() ==> 
  Ford, null, setupownerid=null
getInstance('00exxxxxxxxxxxx') ==> 
  make=Ford, model=Taurus, setupownerid=00exxxxxxxxxxxx
getInstance('005xxxxxxxxxxxx')/getInstance() ==> 
  make=Toyota, model=Taurus, setupownerid=005xxxxxxxxxxxx

Note that getInstance/getOrgDefaults will always return a row with the setupownerid of the ID passed in (or null in the case of getOrgDefaults, and the user id in the case of no-arg getInstance). This is even true if there is no row for the organization and you call getOrgDefaults().

This implies that what you get back from these methods is a derivative of what’s in the DB, potentially all mashed up. Therefore…

Rich’s Rule of Thumb When Working With Custom Settings: Use getValues() when you’re writing custom settings, and use getInstance() when reading them.

Custom Settings and MIXED_DML_OPERATION

16 Mar

Some folks have noticed an issue when using the new Custom Settings feature in Apex. When you have a piece of code that does DML on both a custom setting and a regular object, you get:

"MIXED_DML_OPERATION, DML operation on setup object is not permitted after you have updated a non-setup object (or vice versa)"

What is Mixed DML? Well, certain types of DML simply do not mix well. For instance, if you change a Profile and also an Account (in the same transaction), you might be altering the profile in such a way that it no longer has access to that Account. So, there’s a certain set of combinations that will yield a MIXED_DML_OPERATION exception.

In general, the way to get around this is to do your second bit of DML in a @Future method, as that will happen in its own transaction (though it’s important to note that, in a test method, @Future method invocations are inlined, so you will still get the MIXED_DML_OPERATION exception).

However, starting in version 18.0, Custom Settings are no longer placed in this special bucket. You can now do DML on Custom Setting objects and other (non-setup) objects in the same transaction.

Just be sure your code is set to version 18.0!

Apex Describes and class versions

11 Mar

I‘m resurrecting this blog for posts related to Apex, as using my java.net blog for that purpose would be inappropriate. I’m not sure how often I’ll post. When things of general interest crop up while I’m working on the Apex compiler, I suppose.

Today’s topic came up as part of a customer support escalation. It’s a tricky gotcha with the Apex getMap() function, used for getting all the fields for an sObject type (kind of like reflection for your database objects).

For example, you can get a map of all the fields in the User object by writing:

Map userFields = SObjectType.User.fields.getMap();

With this map, you can see which fields the running user has access to:

boolean b = userFields.get(‘accountid’).getDescribe().isAccessible();

There’s a subtle gotcha with using describes, and a fairly simple rule of thumb:

Don’t pass the map around between classes.

In my example, I’m getting the AccountId field. This field was added in version 17. Let’s say you have two classes, QueryBuilder and DescribeUtil.

// version 16
public class QueryBuilder {
  public String buildQuery {
    Map userFields = DescribeUtil.getUserFields();
    String fieldlist = '';
    for (String key : userFields.keySet()) {
      if (userFields.get(key).getDescribe().isAccessible())
        fieldlist = fieldlist + ',' + key;
    }
  }
}

// version 17
public class DescribeUtil {
  public static Map getUseFields() {
    return SObjectType.User.fields.getMap();
  }
}

You will get an error:

Field User.AccountId is inaccessible in this context

Why? Because QueryBuilder is running in a world where the AccountId field doesn’t exist yet! If the getMap() call were done in QueryBuilder, it wouldn’t be in there.

So, do yourselves a favor and don’t pass these maps around from class to class. The version mismatch is an easy thing to miss.



Moving to java.net

23 Mar

I’m moving this java show over to my new blog on java.net.

At the pub with netbeans folks

24 Feb

There are a bunch of sun developers in town for an internal training seminar on netbeans. I’m the only non-Sun employee speaking at this seminar. I’m giving a little talk on the cluster build harness and my Feedreader tutorial (which won the ipod, BTW).

Anyway, last night a bunch of us got together at a pub in Burlingame. I got to meet Sanjeev of the safari netbeans project, a bunch of folks from the Java Studio Creator team, and more Petr’s than you can shake a stick at :-)

One thing that really surprised me is the sheer number of developers they have working on netbeans. Between the netbeans core team, the JSC team, and other groups working on netbeans-related technologies, we’re talking hundereds. My team has 3.5!

We talked about JDIC in netbeans, mac support (which Tim Boundreau is very keen on, and as of fairly recently, Apple is too), which openapis need to go, and which ones need to be beefed up. It may not always look like it from just reading the mailing lists, but these guys are pretty much on top of what needs to be done, and how to do it.

One of the major hurdles to improving netbeans, I learned, is Sun’s legal department, and their attitude towards integrating open source projects. It’s not enough for the lawyers to approve, say, the Apache License, and have that be the end of it. NO, they need to go through a month or two of painful wrangling for EACH library, even if they’re all covered under the same license! Worse yet, no one knows how to fix this!

Another example: JDIC. It’s LGPL, which makes their lawyers tremble. This is not without reason, as there’s a valid debate about the LGPL as it applies to class files. However, there are 2 problems with this. Firstly, there’s no doubt that the intent of the LGPL as applied to java libraries is to allow developers to drop a jar into the classpath and use it. Secondly, JDIC’s copyright is owned by … Sun! Are they going to sue themselves?!

This kind of insanity could, in my opinion, kill netbeans in the long run. Netbeans can’t be slow on the uptake when adopting open source java technologies. They can’t be reticent to have good support for JDNC, or struts, or anything else, simply because it’s too hard to run through the bureaucracy of putting the library in a module.

It should work the other way, too. Netbeans has had technology like the commons VFS for a long, long time. Why did anyone feel the need to rewrite it?

Tim just wrote a prototype of something he’s hoping will replace SystemOption (it’s in contrib/options). When I told him there was already a commons library for doing exactly the same thing, he said it was easier to rewrite it than get approval to use the commons library.

WTF?!

Follow

Get every new post delivered to your Inbox.