1

我的用户对象上有一些自定义字段,我想在 VisualForce 触发器中使用 APEX 代码访问这些字段。当我从公式字段访问它时,我可以使用一个漂亮的 $User 引用,如下所示:

$User.my_prop__c

从 APEX 我必须通过 UserId 查询 User 对象,如下所示:

[select my_prop__c from User where id = :UserInfo.getUserId()].my_prop__c;

APEX 中是否已经有一些东西可以让我在没有 SOQL 查询的情况下获取用户属性?如果没有,是否有人知道用于延迟加载和缓存用户属性的实用程序类,因此开销最小。

4

2 回答 2

2

我会使用类似于以下代码示例的内容。它使用单例模式在事务期间将信息静态存储在内存中。它类似于 twamley 提出的延迟加载,但我觉得这是一种更简单的方法。

用法一:UserUtil.CurrentUser.Email;

用法2:用户 someUser = UserUtil.getUser(someUserId);

这将允许您访问有关当前用户或系统中其他用户的相同信息。注意 queryUsers 方法只返回一个查询结果。这使得从查询中添加和删除字段变得容易,因为它以自己的方法隔离,使事情变得简单。

注意:此代码在使用时会吸引所有用户。大多数组织没有数百个用户,因此堆大小不应该是一个问题。但如果是,您可以修改 queryUsers() 方法以仅返回活动用户或根据其他条件进行过滤。

public class UserUtil {
//Protected Members
private static final UserUtil instance = new UserUtil();
private Map<Id, User> mapUsers;

//Properties
public static User CurrentUser {
    get { return getUser(UserInfo.getUserId()); }
}

//Constructor
private UserUtil() {
    mapUsers = new Map<Id, User>(queryUsers());
}

//Public Methods
public static User getUser(Id userId) {
    if (instance.mapUsers.containsKey(userId)) {
        return instance.mapUsers.get(userId);
    }
    else {
        throw new InvalidUserIdException('Unable to locate user id: ' + userId);
    }
}

//Private Methods
private List<User> queryUsers() {
    return [SELECT 
                Id
                , Name
                , UserName
                , Email
                , Alias 
            FROM 
                User];
}

//Internal Classes
public class InvalidUserIdException extends Exception {}

}

于 2012-07-11T22:49:33.747 回答
0

我编写了自己的实用程序类。不过,我仍然对更好的技术感兴趣。此实用程序类在访问第一个属性时延迟加载。Update_Closed_Won_Opportunities__c 和 Set_Opportunities_to_Closed_Won__c 是我在用户对象上的自定义字段(仅对系统管理员可见,因此人们无法升级他们的权限)。

public with sharing class MyUserInfo {
    private Id userId;
    private User myUser; // Hold onto the user object once we've loaded it

    // Default constructor uses the active user id
    public MyUserInfo() {
        userId = UserInfo.getUserId();
    }

    // Secondary constructor accepts a user id as a parameter
    public MyUserInfo(Id someOtherUserId) {
        userId = someOtherUserId;       
    }

    // Only called one time when we first need it so grab all of the custom fields now
    private void LazyLoadUser() {
        System.AssertNotEquals(null, userId);
        myUser = [
            SELECT Update_Closed_Won_Opportunities__c, Set_Opportunities_To_Closed_Won__c
            FROM User 
            WHERE id = :userId
        ];
        System.AssertNotEquals(null, myUser, 'Unable to load user with id ' + userId); // could return defaults instead
    }

    // Getters (be sure to include each field in the SOQL of LazyLoadUser)
    public boolean UpdateClosedWonOpportunities { get {
        if (myUser == null) LazyLoadUser();
        return myUser.Update_Closed_Won_Opportunities__c;
    } }
    public boolean SetOpportunitiesToClosedWon { get {
        if (myUser == null) LazyLoadUser();
        return myUser.Set_Opportunities_To_Closed_Won__c;
    } }
}

这是我使用该课程的触发器。第一行myUserInfo = new MyUserInfo();不运行任何 SOQL。在使用第一个自定义 get 属性之前不会发生这种情况。后续调用不需要 SOQL。

trigger LockClosedOpportunity on Opportunity (before update) {
    MyUserInfo myUserInfo = new MyUserInfo();
    for (Opportunity o : trigger.old)
    {
        if (!myUserInfo.UpdateClosedWonOpportunities && o.StageName == 'Closed Won')
            trigger.newMap.get(o.Id).addError('You do not have permission to change an Opportunity after it has been set to Closed Won.');
    }
    for (Opportunity o : trigger.new)
    {
        if ( !myUserInfo.SetOpportunitiesToClosedWon && o.StageName == 'Closed Won' && trigger.oldMap.get(o.Id).StageName != 'Closed Won' )
            o.addError('You do not have permission to set an Opportunity to Closed Won.');
    }
}

它在公式中读起来类似于 $User,当一个(或零个)就足够了时,我不必担心执行多个 SOQL 调用。

于 2012-07-10T21:51:24.960 回答