Asynchronous 根据上次登录日期取消对用户的激活

Asynchronous 根据上次登录日期取消对用户的激活,asynchronous,salesforce,apex,Asynchronous,Salesforce,Apex,场景:从今天起停用登录日期小于42的用户。我有一个用户的最后登录日期是2020年1月22日(美国日期格式)/2020年1月22日下午5:12。在这里,我编写了一个用于停用的批处理apex。我的代码已成功执行,批处理状态已完成,但用户记录未停用 代码如下: global class User_Deactivation implements Database.Batchable<SObject> { dateTime dt = date.today()-42; public

场景:从今天起停用登录日期小于42的用户。我有一个用户的最后登录日期是2020年1月22日(美国日期格式)/2020年1月22日下午5:12。在这里,我编写了一个用于停用的批处理apex。我的代码已成功执行,批处理状态已完成,但用户记录未停用

代码如下:

global class User_Deactivation implements Database.Batchable<SObject>
{
dateTime dt = date.today()-42;
       public String query = 'SELECT Name, LastLoginDate, Id From User WHERE IsActive = true AND LastLoginDate=:dt   ';


    global Database.querylocator start(Database.BatchableContext bc)
    {
       return Database.getQueryLocator(query);
    }

    global void execute(Database.BatchableContext bc,List<User> scope)
    {
        List<User> userList = new List<User>();

        for(User s:scope)
        {
            User u =(user)s;
            userList.add(u);
        }

        if(userList.size() > 0)
        {
            for(User usr : userList)
            {
                usr.isActive = false;
            }
        }
        update userList;
    }

    global void finish(Database.BatchableContext bc)
    {
        AsyncApexJob a = [SELECT Id, Status, NumberOfErrors, JobItemsProcessed, TotalJobItems, CreatedBy.Email
                          FROM AsyncApexJob 
                          WHERE Id = :BC.getJobId()];

        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        String[] toAddresses = new String[] {a.CreatedBy.Email};
        mail.setToAddresses(toAddresses);
        mail.setSubject('Apex Job Status: ' + a.Status);
        mail.setPlainTextBody('The batch Apex job processed ' + a.TotalJobItems + ' batches with '+ a.NumberOfErrors + ' failures.');
        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
    }
}
全局类用户\停用实现数据库。可批处理
{
dateTime dt=日期。今天()-42;
publicstringquery='从用户中选择名称、LastLoginDate、Id,其中IsActive=true,LastLoginDate=:dt';
global Database.querylocator启动(Database.BatchableContext bc)
{
返回数据库.getQueryLocator(查询);
}
全局void execute(Database.BatchableContext bc,列表范围)
{
List userList=新列表();
用于(用户:范围)
{
用户u=(用户)s;
userList.add(u);
}
if(userList.size()>0)
{
for(用户usr:userList)
{
usr.isActive=false;
}
}
更新用户列表;
}
全局void完成(Database.BatchableContext bc)
{
AsyncApexJob a=[选择Id、状态、NumberOfErrors、JobItemsProcessed、TotalJobItems、CreatedBy.Email
从AsyncApexJob
其中Id=:BC.getJobId();
Messaging.SingleEmailMessage mail=新建消息。SingleEmailMessage();
String[]toAddresses=新字符串[]{a.CreatedBy.Email};
mail.setToAddresss(ToAddresss);
mail.setSubject('Apex作业状态:'+a.Status);
mail.setPlainTextBody('批处理作业处理了'+a.TotalJobItems+'批处理,其中'+a.NumberOfErrors+'失败');
Messaging.sendmail(newmessaging.SingleEmailMessage[]{mail});
}
}

请在这方面帮助我

这里有很多你可以改进的地方,我从哪里开始

初始化(?)块

dateTime dt = date.today()-42;
String query = 'SELECT Name, LastLoginDate, Id From User WHERE IsActive = true AND LastLoginDate=:dt';
您需要日期或日期时间匹配吗?你写它的方式只会匹配那些在午夜登录的人<代码>系统调试(dt)会说
2020-01-23T00:00:00.000Z
。它不应该是等号,应该是“小于”或“小于或等于”

或者更好——你可以把你想做的事情说得更清楚一点,说得更“语义化”,这样维护它的可怜的家伙就可以理解它,而不需要额外的注释。这读起来更自然,并使用特殊的“常量”简化逻辑:
SELECT Id,LastLoginDate FROM User,其中isActive=true和LastLoginDate!=最后天数:42

这段代码到底是什么。它不是真正的静态变量,也不是构造函数。。。我认为它会表现为一个构造函数。对批量的构造函数要非常非常小心。每次计划运行类时,都会保存(序列化)并还原构造函数末尾的类状态。在构造函数中加入一些初始化代码很有诱惑力,也许可以阅读一些自定义设置,预先计算的东西。。。但是当管理员添加了新的自定义设置,而批处理没有接收到它时,您会感到非常惊讶。在您的情况下,更糟糕的是,我怀疑它会序列化
dt
,而您的
today()
将被冻结,而不是您所期望的。为安全起见,将所有初始化逻辑移至
start()

我甚至会说,给你这个要求的人都没有考虑清楚。当你创建新用户时,他们会得到一个链接,他们需要在接下来的72小时内点击。如果他们没有这样做(可能是星期五晚些时候发送的,他们想在星期一登录)-这件事会在星期五晚上尽职地终止他们的访问,而不会给他们任何登录的机会。你需要一些“宽限期”。可能类似于
其中isActive=true和(LastLoginDate<:x或(LastLoginDate=null和CreatedDate<:x))

start()

字符串中的查询是有效的,很多批处理文档都是这样编写的,但它们的实践效果很差。在可能的情况下,使用括号中的已编译查询。您在执行(预编译)方面得到了最小的改进,在出现问题时会得到编译时警告(比不监视作业时可能不会注意到的运行时错误要好)。最重要的是,如果有人想删除一个字段,SF将检测到依赖项并阻止他/她。使用
返回数据库.getQueryLocator([选择…])无论你在哪里都可以

execute()

您的
范围
已经是一个用户列表,为什么要对用户进行额外的强制转换?为什么要将它们添加到帮助器列表中?为什么是2圈

for(User u : scope){
    u.isActive = false;
}
update users;
你做完了吗

还有,为什么到处都是“全球”