Qrartz.net DailyTimeIntervalScheduleBuilder - How to identity first and last execution of the trigger in a day - quartz.net-3.0

Trying to Identity the first and last execution of a trigger in a day when quartz.net fire Execute(IJobExecutionContext context). Is there any way to to find this in quartz.net Execute(IJobExecutionContext context) method?

IEnumerable<DateTime> firingTimes = context.Trigger.GetNextFiringTimes(DateTimeOffset.Now.Date, DateTimeOffset.Now.Date.AddDays(1));
public static class TriggerExts
{
public static IEnumerable<DateTime> GetNextFiringTimes(this ITrigger trigger, DateTimeOffset? after = null, DateTimeOffset? before = null)
{
ITrigger temp = trigger.Clone();
after = after ?? DateTimeOffset.Now;
DateTimeOffset? next = temp.GetFireTimeAfter(after);
before = before ?? next.Value.AddYears(1);
while (next.HasValue && next.Value < before)
{
yield return next.Value.LocalDateTime;
next = temp.GetFireTimeAfter(next.Value);
}
}
}

Related

Add AttachToTransaction to action in FastCrud

I'm trying to make a UnitOfWork/Repository pattern using fastcrud.
I have created a generic repository
public interface IRepository<T> where T : BaseEntity
{
IDbTransaction Transaction { get; set; }
T Get(T entityKeys, Action<ISelectSqlSqlStatementOptionsBuilder<T>> statementOptions = null);
IEnumerable<T> Find(Action<IRangedBatchSelectSqlSqlStatementOptionsOptionsBuilder<T>> statementOptions = null);
int Count(Action<IConditionalSqlStatementOptionsBuilder<T>> statementOptions = null);
bool Delete(T entityToDelete, Action<IStandardSqlStatementOptionsBuilder<T>> statementOptions = null);
}
From the service I call
var repo = UnitOfWork.GetRepository<MyTable>();
var myList = repo.Find(statement => statement
.AttachToTransaction(repo.Transaction)
.OrderBy($"{nameof(MyTable.Name):C}")
);
This works. But I don't want the service to handle the AttachToTransaction call, instead i would like to add it to my repository
public IEnumerable<T> Find(Action<IRangedBatchSelectSqlSqlStatementOptionsOptionsBuilder<T>> statementOptions = null)
{
return Connection.Find<T>(statementOptions);
}
But here the statementOption is a delegated Action, and I can't do
statementOption.AttachToTransaction(this.Transaction)
My UnitOfWork always creates an transaction, so if I skip attaching to transaction it I will get an exception
An unhandled exception occurred while processing the request.
InvalidOperationException: ExecuteReader requires the command to have a transaction when the connection assigned to the command is in a pending local transaction. The Transaction property of the command has not been initialized.
You can do it like this:
public IEnumerable<T> Find(Action<IRangedBatchSelectSqlSqlStatementOptionsOptionsBuilder<T>> statementOptions = null)
{
statementOptions += s => s.AttachToTransaction(this.Transaction);
return Connection.Find<T>(statementOptions);
}
I had the same issue too. I have used this extension method resolved it:
internal static IRangedBatchSelectSqlSqlStatementOptionsOptionsBuilder<TEntity> AttachToTransaction<TEntity>(
this IRangedBatchSelectSqlSqlStatementOptionsOptionsBuilder<TEntity> statement,
Action<IRangedBatchSelectSqlSqlStatementOptionsOptionsBuilder<TEntity>> originalStatementOptionsBuilder,
IDbTransaction transaction)
{
if (originalStatementOptionsBuilder == null)
{
statement.AttachToTransaction(transaction);
}
else
{
originalStatementOptionsBuilder(statement);
statement.AttachToTransaction(transaction);
}
return statement;
}
Now your service must change like this:
public IEnumerable<T> Find(Action<IRangedBatchSelectSqlSqlStatementOptionsOptionsBuilder<T>> statementOptions = null)
{
return Connection.Find<T>(s => s.AttachToTransaction(statementOptions, this.Transaction));
}

Entity Framework 6 Disable Interception temporarily

I am using an IDbCommandTreeInterceptor to enable soft deletes on my model.
System.Data.Entity.Infrastructure.Interception.DbInterception.Add(
new SoftDeleteInterception());
I want to be able to disable the interceptor temporarily so that I can select a "deleted" entity for auditing purposes.
However, It seems like the DbInterception collection is assembly-wide.
Is there any way to create a new DbContext without interception on?
Or even a way to add the interceptor to the DbContext every time it is created?
I have extended my db context class with additional property
[DbConfigurationType(typeof(DbConfig))]
public partial class YourEntitiesDB
{
public bool IgnoreSoftDelete { get; set; }
}
Then in the TreeCreated(...) method i check this flag and if true then it just doesn't go further to the QueryVisitor
public class SoftDeleteInterceptor : IDbCommandTreeInterceptor
{
public SoftDeleteInterceptor()
{
}
public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext)
{
var db = interceptionContext.DbContexts.FirstOrDefault() as YourEntitiesDB;
if (db!=null && db.IgnoreSoftDelete)
{
// Ignore soft delete interseptor (Used in archives)
return;
}
if (interceptionContext.OriginalResult.DataSpace == DataSpace.CSpace)
{
var queryCommand = interceptionContext.Result as DbQueryCommandTree;
if (queryCommand != null)
{
var newQuery = queryCommand.Query.Accept(new SoftDeleteQueryVisitor());
interceptionContext.Result = new DbQueryCommandTree(
queryCommand.MetadataWorkspace,
queryCommand.DataSpace,
newQuery);
}
var deleteCommand = interceptionContext.OriginalResult as DbDeleteCommandTree;
if (deleteCommand != null)
{
var column = SoftDeleteAttribute.GetSoftDeleteColumnName(deleteCommand.Target.VariableType.EdmType);
if (column != null)
{
var setClauses = new List<DbModificationClause>();
var table = (EntityType)deleteCommand.Target.VariableType.EdmType;
if (table.Properties.Any(p => p.Name == column))
{
setClauses.Add(DbExpressionBuilder.SetClause(
DbExpressionBuilder.Property(
DbExpressionBuilder.Variable(deleteCommand.Target.VariableType, deleteCommand.Target.VariableName),
column),
DbExpression.FromBoolean(true)));
}
var update = new DbUpdateCommandTree(
deleteCommand.MetadataWorkspace,
deleteCommand.DataSpace,
deleteCommand.Target,
deleteCommand.Predicate,
setClauses.AsReadOnly(),
null);
interceptionContext.Result = update;
}
}
}
}
}
In order to use it i just set the flag to true when needed
YuorEntitiesDB DB = new YuorEntitiesDB();
DB.IgnoreSoftDelete = true;
DB.Records.Where(...)

Npgsql 3.1.0-alpha5 does not allow passing null into a TIMESTAMP parameter for a function

I've been experimenting with coreclr on linux using the beta Npgsql library (3.1.0-alpha5). When passing parameters to a function, the library throws errors anytime a TIMESTAMP parameter is null: "Parameter <blah> must be set". Below is a test case.
create sequence sq_category_id start 1 increment 1;
create table category (
id int not null default nextval('sq_category_id'),
name varchar(16) not null,
date timestamp with time zone not null default (now() at time zone 'utc'),
active bool not null default (true),
constraint pk_category_id primary key (id),
constraint uq_category_name unique (name)
);
.. and the function
-- update
create or replace function fn_category_update(
p_id integer,
p_name character varying(16),
p_date timestamp with time zone,
p_active boolean
) returns json as
$$
declare result json = json_build_object('id', null, 'name', null, 'date', null, 'active', null);
begin
update category set
name = case
when
p_name is not null and
p_name != name and
rtrim(ltrim(p_name)) != ''
then p_name
else name
end,
date = case
when
p_date is not null and
p_date != date
then p_date
else date
end,
active = case
when
p_active is not null and
p_active != active
then p_active
else active
end
where id = p_id returning json_build_object('id', id, 'name', name, 'date', date, 'active', active) into result;
return result;
exception when others then return result;
end
$$
language plpgsql;
Anyone have an idea of what I might be doing wrong?
**Edit, here is the c# code along with the exception stack trace (which doesn't provide much additional information).
using System;
namespace Landress.Co.Models.DataObjects
{
public class CategoryDataObject
{
public int? Id { get; set; }
public string Name { get; set; }
public DateTime? Date { get; set; }
public bool? Active { get; set; }
public CategoryDataObject(int? id = null, string name = null, DateTime? date = null, bool? active = null)
{
this.Id = id;
this.Name = name;
this.Date = date;
this.Active = active;
}
public CategoryDataObject()
{
this.Id = null;
this.Name = null;
this.Date = null;
this.Active = null;
}
}
}
The code which actually makes the call to the function:
public CategoryDataObject Update(CategoryDataObject item)
{
NpgsqlConnection conn = new NpgsqlConnection(Configuration.GetSection("Data:DefaultConnection").Value);
try
{
conn.Open();
NpgsqlCommand cmd = new NpgsqlCommand("fn_category_update", conn);
cmd.CommandType = CommandType.StoredProcedure;
var paramId = cmd.CreateParameter();
paramId.ParameterName = "p_id";
paramId.NpgsqlDbType = NpgsqlTypes.NpgsqlDbType.Integer;
paramId.IsNullable = false;
paramId.Value = item.Id;
cmd.Parameters.Add(paramId);
var paramName = cmd.CreateParameter();
paramName.ParameterName = "p_name";
paramName.NpgsqlDbType = NpgsqlTypes.NpgsqlDbType.Varchar;
paramName.Size = 16;
paramName.IsNullable = true;
paramName.Value = item.Name;
cmd.Parameters.Add(paramName);
var paramDate = cmd.CreateParameter();
paramDate.ParameterName = "p_date";
paramDate.NpgsqlDbType = NpgsqlTypes.NpgsqlDbType.Timestamp;
paramDate.IsNullable = true;
paramDate.Value = item.Date;
cmd.Parameters.Add(paramDate);
var paramActive = cmd.CreateParameter();
paramActive.ParameterName = "p_active";
paramActive.NpgsqlDbType = NpgsqlTypes.NpgsqlDbType.Boolean;
paramActive.IsNullable = true;
paramActive.Value = item.Active;
cmd.Parameters.Add(paramActive);
string jsonResult = String.Empty;
try
{
jsonResult = cmd.ExecuteScalar().ToString();
cmd.Dispose();
conn.Close();
conn.Dispose();
try
{
return JsonConvert.DeserializeObject<CategoryDataObject>(jsonResult);
}
catch (Exception ex)
{
Console.WriteLine(String.Format("Unable to deserialize json result returned from postgresql: {0}", ex.Message));
return new CategoryDataObject();
}
}
catch (Exception ex)
{
Console.WriteLine(String.Format("Unable to execute postgresql function \"fn_category_update\": {0}", ex.Message));
return new CategoryDataObject();
}
}
catch (Exception ex)
{
Console.WriteLine(String.Format("Unable to open a connection to the database: {0}", ex.Message));
return new CategoryDataObject();
}
}
and finally the full stack trace.
-- Stack Trace
at Npgsql.NpgsqlParameter.ValidateAndGetLength()
at Npgsql.NpgsqlCommand.ValidateAndCreateMessages(CommandBehavior behavior)
at Npgsql.NpgsqlCommand.ExecuteScalarInternal()
at Landress.Co.Models.Repositories.CategoryRepository.Update(CategoryDataObject item) in C:\Users\<userName>\Desktop\landress.co\src\landress.co\Models\Repositories\CategoryRepository.cs:line 73
-- Message
Parameter p_date must be set
Should have used System.DBNull instead of null to represent value passed to the function. Not an issue with the library at all.

Apex Test Class - How to set a rollup count field in a test class

Trying to set a value for a roll up summary field in the test class to improve code coverage. How do I do it?
public class clsPreferredIASetExt {
List<PreferredIA__c> preferredias;
public static PreferredIA__c[] tobeClosed = new PreferredIA__c[0];
public static PreferredIA__c[] newPreIAs = new PreferredIA__c[0];
public static PreferredIA__c loopadd;
public static PreferredContact__c[] contactlists = new PreferredContact__c[0];
public static Account[] InvoicedAccounts = new Account[0];
public static PreferredIA__c[] monkey;
public clspreferrediaSetExt(ApexPages.StandardSetController controller) {
preferredias = (List<PreferredIA__c>) controller.getSelected();
}
public void getInitCloseInv() {
tobeclosed = [select id, Account__c, Account__r.id, Account__r.Name,
Account__r.AccountNumber, Specialist__c,
PreferredInvoice__c, Status__c
from PreferredIA__c where Status__c = 'Invoiced' limit 150];
list<string> testme = new list<string>{};
for(PreferredIA__c a:tobeclosed) {
testme.add(a.Account__r.id);
}
InvoicedAccounts = [select id, EligibleIAs__c, PreferredOverride__c,
Preferred_Territory__r.rep__c, LastSurveyDate__c,
InitialInspectionComplete__c, Program_level__c,
PreferredExempt__c, Account_Status__c,
Active_IAs__c, Last_Training__c
from Account where id IN :testme];
Contactlists = [select id, Account__c
from PreferredContact__c where Account__c IN :testme];
for(PreferredIA__c q:tobeclosed) {
q.Status__c = 'Closed';
}
for(Account z:invoicedaccounts) {
/****************************************************************
The following condition is where I am trying to set the z.EligibleIAs__c
which is a roll up count field of PreferredIA__c objects associated with
the account.
****************************************************************/
if(z.EligibleIAs__c == 0
&& z.Program_Level__c == 'Preferred'
&& !z.PreferredExempt__c
&& (z.Account_Status__c == 'Active'
|| z.Account_Status__c == 'Product Only')) {
loopadd = new PreferredIA__c();
system.debug(z.id);
system.debug(z.Account_Status__c);
loopadd.Account__c = z.id;
if(z.PreferredOverride__c != null) {
loopadd.Specialist__c = z.PreferredOverride__c;
}
else {
loopadd.Specialist__c= z.Preferred_territory__r.Rep__c;
}
for(PreferredContact__c q:contactlists) {
if(q.Account__c == z.id) {
loopadd.PreferredContact__c = q.id;
}
}
loopadd.CreatedDate__c = Date.Today();
if(z.Last_training__c != null) {
loopadd.DueDate__c = z.Last_Training__c.AddDays(365);
}
else {
loopadd.DueDate__c = Date.Today().AddDays(365);
}
loopadd.initial__c = false;
loopadd.Status__c = 'Unacknowledged';
newPreIAs.add(loopadd);
}
z.InitialInspectionComplete__c = true;
}
try {
update tobeclosed;
update invoicedaccounts;
insert newPreIAs;
}
catch(system.dmlexception q) {
system.debug(q);
system.debug(invoicedaccounts);
system.debug(newPreIAs);
}
}
public void ReceivePPW() {
monkey = [select id, Status__c from PreferredIA__c
where id in :preferredias and status__c = 'Training Completed'];
for (PreferredIA__c m:monkey) {
m.status__c = 'Awaiting Invoice';
}
update monkey;
}
}
I can't actually see where you're trying to write to the field — or did you remove it because it wasn't working?
That aside, the answer is that you can not write to a roll-up summary field. If you require a value in that field you should insert child records to your parent test records, with appropriate field values such that your summary field calculates a value.
Also, I can see that you're querying PerferredIA__c at the start, your test methods should never depend on data being in the system already, you should insert your records yourself in your test code. The reason for this is that if you try to deploy to an org which has no relevant data, your tests will fail and so, subsequently, will your deployment.
For situations like these, consider mock objects (or just variables simulating expected values), similar to inserting test values as Lacey suggests. This technique is required to achieve 100% coverage when doing callouts, for example, since they terminate tests at the moment of the call.

How to resolve Object Manager has been closed error?

I'll appreciate if someone can point me to a tutorial or best practice on how to close
JDO connection.
I constantly get javax.jdo.JDOUserException: Object Manager has been closed error whenever I include the finally block.
My code is below:
public static List<AgentEntity> findAgentEntityByString(String id) {
List<AgentEntity> agententity = new ArrayList<AgentEntity>();
if (id == null) {
return null;
}
try {
Query q = pm.newQuery("select id from " + AgentEntity.class.getName());
agententity = (List<AgentEntity>) q.execute();
} catch(Exception ex) {
log.warning(ex.getMessage());
}
return agententity;
}
Regards
One possible solution to avoid this lazy loading problem is to use the size() method forcing the PersistenceManager object to load the result list from datastore before being closed.
public static List<AgentEntity> findAgentEntityByString(String id) {
List<AgentEntity> agententity = new ArrayList<AgentEntity>();
if (id == null) {
return null;
}
try {
Query q = pm.newQuery("select id from " + AgentEntity.class.getName());
agententity = (List<AgentEntity>) q.execute();
agententity.size() //Should populate the returned list
return agententity;
} finally {
pm.close();
}
}
Reference here.
Why do you want to close your PersistenceManager here ?
If you want to close the Query you should use either
javax.jdo.Query.closeAll() or javax.jdo.Query.close(Object result).
So you can do either a transient copy of the result and than close the query and its result:
public static List<AgentEntity> findAgentEntityByString(String id) {
if (id == null) {
return null;
}
Query q = null;
try {
q = pm.newQuery("select id from " + AgentEntity.class.getName());
return new ArrayList<AgentEntity>((List<AgentEntity>) q.execute());
} finally {
if(q!= null){
q.closeAll();
}
}
}
or you can close the result later explicitly:
public static List<AgentEntity> findAgentEntityByString(String id) {
if (id == null) {
return null;
}
Query q = pm.newQuery("select id from " + AgentEntity.class.getName());
return (List<AgentEntity>) q.execute();
}
}
....
List agents = X.findAgentEntityByString("Foobar");
....
pm.close(agents);
Try setting the fetch plan just after getting the PM, then setting it to all before you perform your query:
import javax.jdo.FetchPlan;
pm = PMF.get().getPersistenceManager();
FetchPlan fp = pm.getFetchPlan();
fp.setGroup(FetchPlan.ALL);
Actually, what fixed this for me is answered here:
Why do I get "Persistence Manager has been closed" exception
I had an instance reference to the persistence manager, I just made a local instance and all my errors fixed

Resources