Create apex rollup triggers - triggers

I am looking to replace the rollups in my Salesforce rollup helper with apex versions, and run those instead. I am trying to transform the following into Apex code. Please let me know if you have any ideas.

This is a very straight forward use case for Apex. You need to create a Trigger on the child object that will do the math and update the parent object.
Best Practices dictate that the Trigger should actually call a method in a class, but here is an abbreviated version of the solution:
trigger myTrigger on Collateral__c (after insert, after update){
Map<Id, Deal__c> dealMap = new Map<Id, Deal__c>();
for ( Collateral__c c : Trigger.new ){
dealMap.put( c.Deal__c, new Deal__c( Id=c.Deal__c, Total_Lendable_Collateral__c=0) );
}
for ( AggregateResult ar : [
SELECT Deal__c parentId, SUM(Lendable_Value__c) s
FROM Collateral__c
WHERE Deal__c IN :dealMap.keySet()
]){
Id i = (Id)ar.get('parentId');
dealMap.put( i, new Deal__c(Id=i,Total_Lendable_Collateral__c=(Decimal)ar.get('s')));
}
update dealMap.values();
}

Related

cassandra trigger create vs update

I need to implement a cassandra trigger in java that will take a different action for INSERT vs UPDATE operations.
I've seen how it is possible to identify a DELETE operation in the question Cassandra sample trigger to get the deleted row and column values but I can't see any methods in the ColumnFamily object that would allow allow the code to differentiate between INSERT vs UPDATE, is there a way to achieve this?
There isn't conceptually any difference between INSERT and UPDATE. Indeed an INSERT and an UPDATE are just mutation. Cassandra gives them different name so that people coming from the relational DB have familiar concepts
As #doanduyhai mentioned and according to Casssandra sources only INSERT operation updates row timestamp (LivenessInfo).
For other operations this timestamp is not updated and equals Long.MIN_VALUE.
Custom Trigger which checks for INSERT operation
public class CustomTrigger implements ITrigger {
#Override
public Collection<Mutation> augment(Partition partition) {
checkQueryType(partition));
return Collections.emptyList();
}
private void checkQueryType(Partition partition) {
UnfilteredRowIterator it = partition.unfilteredIterator();
while (it.hasNext()) {
Unfiltered unfiltered = it.next();
Row row = (Row) unfiltered;
if (isInsert(row)) {
// Implement insert related logic
}
}
}
private boolean isInsert(Row row) {
return row.primaryKeyLivenessInfo().timestamp() != Long.MIN_VALUE;
}
}

how to insert and update record through trigger in a custom object in salesforce

Hi I have tried the below code
trigger CreateRecord on Account (before insert,before update) {
List<Account> CreateAcc = new List<Account>();
For(Account acc:trigger.new)
{
acc.Name='abc';
CreateAcc.add(acc);
}
insert CreateAcc;
}
but the above code is creating the following error :
Review all error messages below to correct your data.
Apex trigger CreateRecord caused an unexpected exception, contact your administrator: CreateRecord: execution of BeforeInsert caused by: System.SObjectException: DML statement cannot operate on trigger.new or trigger.old: Trigger.CreateRecord: line 9, column 1enter code here
Please help me through the code as where I am wrong.
Why don't you try to call a methods or function from a controller rather than putting your stuffs in trigger ?
On my end, I would do it like this ..
Create a utility controller with a methods that will insert a record
public class UtilityController
{
#future (callout = true)
public static void CreateRecord()
{
//Put your stuffs here...
}
}
And then in the trigger, just call that method
trigger Account_CreateNewRecord on Account (before insert,before update) {
Utility.CreateRecord();
}
Note that you can only call a method/function from another class if it has a future anotation.
I often use triggers like this to call a method on or before/after statement.
That way you're trigger was just focus on executing a method/function when it was triggered.
See Apex Developers Guide for more information about apex triggers.
Remove the update DML statement at the end. By using the "before" trigger to modify the Trigger.new objects, you don't need to explicitly perform an update, insert a DML statement. When the trigger ends, it will implicitly update or insert the data as you have modified the values.
trigger CreateRecord on Account (before insert,before update) {
List<Account> CreateAcc = new List<Account>();
For(Account acc:trigger.new)
{
acc.Name='abc';
CreateAcc.add(acc);
}
//insert CreateAcc; removed this line.
}

how to insert parent child while doing entityframework.bulkinsert?

I am using Entityframework 6, I am trying to insert a parent-child kind of data in the database.
I am using Entityframework.BulkInsert to insert data. I have autoIncrement int primary key in all the tables
My object is as follows :
var parentObjects= new List<parentObject>();
var childObjects= new List<childObject>();
for (int i = 0; i <= 100; i++)
{
var parentObj= new parentObject()
{
Name="p1",
Address="a1"
};
childObjects= SeedInitializer.ChildItems.OrderBy(x => new Random().Next()).Take(2).ToList();//this gets 2 child objects
foreach (var childObj in childObjects)
{
childObj .ParentObject= parentObj;
//childObj .CommissionPlanId = i; //tried this still not working
parentObj.ChildObjects.Add(childObj );
}
parentObjects.Add(parentObj);
}
//when I do a quickwatch on parentObjects, i see child objects in each parentObject, but
//with the last id of parentObject
context.BulkInsert(parentObjects, 1000);
context.SaveChanges();
On save only 2 records are created in the childObject are created with a wrong parentObject id i.e. 0
I am not able to understand why child items are not getting created, while parent objects are getting created. Can someone help me understand where I am doing the mistake ?
Disclaimer: I'm the owner of EntityFramework.BulkInsert
You cannot.
This feature has never been implemented.
Disclaimer: I'm the owner of Entity Framework Extensions
However, this new library (not free), can easily handle this kind of scenario.
The BulkSaveChanges work exactly like SaveChanges (handle parent/child) but way faster!
All methods are supported:
Bulk SaveChanges
Bulk Insert
Bulk Delete
Bulk Update
Bulk Merge
Example
// Easy to use
context.BulkSaveChanges();
// Easy to customize
context.BulkSaveChanges(bulk => bulk.BatchSize = 100);
I do not think there is an easy way to accomplish this task, because in order to insert the children, you have to actually finish inserting the parents and get their ids. Normal EF inserts have the advantage that each INSERT will also embed a SELECT to fetch just generated identifier, so that it can use to push it for children (if any).
One possible solution is the following:
Add a Guid RefProperty to the ParentObject type which is also persisted
Add a Guid BatchId to the ParentObject type which is also persisted
Add a Guid RefProperty to the ChildObject type which is not persisted
Save the whole structure by using the following (mainly pseudocode) sequence
var batchId = new Guid();
parentObjects.ForEach(item => item.BatchId = batchId);
// set RefProperty for all parents and children to reflect proper parentation
TransactionScope scope = null;
try
{
context.BulkInsert(parentObjects, 1000);
var newParents = context.ParentObjects.Where(_ => _.BatchId = batchId);
var refPropMap = newParents.ToDictionary(_ => _.RefProperty, _ => ParentId);
var childObjects.ForEach(item => item.ParentId = refPropMap[item.RefProperty]);
context.BulkInsert(childObjects, 1000);
DataAccess.SaveChanges();
scope.Complete();
}
catch (Exception exc)
{
scope?.Dispose();
}
Note: this is not tested
This is quite ugly, but it should do the trick: minimize round-trips to SQL Server and still be one single transaction.
In order to make the SELECT faster, an index on ParentObject table should be placed on BatchId including (covering) its key.
Alternative: change design for these tables to not use auto-increments, but UNIQUEIDENTIFIER columns. This way, all identifiers can be set before making the inserts.

greendao and sqlite triggers

I tried to use the code below to ensure referential integrity in my database, but seems not to be working with GreenDao. I can still delete all the records. On the other hand, when I try to delete in Sqlitemanager, the trigger is raised and delete operation fails.
DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, Common.DBNAME, null)
{
#Override
public void onCreate(SQLiteDatabase db) {
super.onCreate(db);
db.execSQL("CREATE TRIGGER grupe_artikli BEFORE DELETE ON groups "+
"FOR EACH ROW BEGIN "+
"SELECT CASE " +
"WHEN ((SELECT id_group FROM products WHERE id_group = OLD._id) IS NOT NULL) "+
"THEN RAISE(ABORT, 'error') "+
"END; END;");
DaoSession session = new DaoMaster(db).newSession();
}
Does GreenDao support triggers, or is there another method to maintain database referential integrity?
greenDAO has no built-in trigger support. However, I cannot think of any reason why your approach should not work. greenDAO does not hijack the database or something, so you should be able to work directly with the database just like you wouldn't use greenDAO at all.

Does Entity Framework support circular references?

I have two entities in parent/child relationship. In addition, parent contains a reference to a "main" child, so the simplified model looks like this:
class Parent
{
int ParentId;
int? MainChildId;
}
class Child
{
int ChildId;
int ParentId;
}
The problem I am experiencing now is that EF does not seem to be able to handle creation of both Parent and Child in a single operation. I am getting an error "System.Data.UpdateException: Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements, or store-generated values."
MainChildId is nullable, so it should be possible to generate a parent, a child and then update a parent with the newly generated ChildId. Is this something that EF does not support?
No, it's supported. Try it with a GUID key or an assignable sequence. The error means exactly what it says it does: The EF can't figure out how to do this in one step. You can do it in two steps, though (two calls to SaveChanges()).
I had this exact issue. The apparent "Circular reference" is simply good database design. Having a flag on the child table like "IsMainChild" is bad design, the attribute "MainChild" is a property of the parent not the child, so an FK in the parent is appropriate.
EF4.1 needs to figure out a way to handle these type of relationships natively and not force us to redesign our databases to accommodate deficiencies in the framework.
Anyhow my workaround is to do it several steps (like you might when writing a stored procedure to do the same) the only wrinkle is to get round the change tracking on the context.
Using context As New <<My DB Context>>
' assuming the parent and child are already attached to the context but not added to the database yet
' get a reference to the MainChild but remove the FK to the parent
Dim child As Child = parent.MainChild
child.ParentID = Nothing
' key bit detach the child from the tracking context so we are free to update the parent
' we have to drop down to the ObjectContext API for that
CType(context, IObjectContextAdapter).ObjectContext.Detach(child)
' clear the reference on the parent to the child
parent.MainChildID = Nothing
' save the parent
context.Parents.Add(parent)
context.SaveChanges()
' assign the newly added parent id to the child
child.ParentID = parent.ParentID
' save the new child
context.Children.Add(child)
context.SaveChanges()
' wire up the Fk on the parent and save again
parent.MainChildID = child.ChildID
context.SaveChanges()
' we're done wasn't that easier with EF?
End Using
Both EF and LINQ to SQL have this problem of not being able to save circular references, even though they could be a lot more helpful by just encapsulating 2 or more SQL calls in a transaction behind the scenes for you instead of throwing an Exception.
I wrote a fix for this in LINQ to SQL but haven't gotten around to doing so in EF yet, because I've just been avoiding circular references in my db design for the time being.
What you can do is create a helper method that sets aside circular references, run that before calling SaveChanges(), run another method that puts the circular references back in place, and call SaveChanges() again. You can encapsulate all of that in a single method, maybe SaveChangesWithCircularReferences().
To put the circular references back, you need to track what you removed and return that log.
public class RemovedReference() . . .
public List<RemovedReference> SetAsideReferences()
{
. . .
}
So basically the code in SetAsideReferences is hunting down circular references, setting aside one half in each case, and recording those in a list.
In my case I created a class that stored the object, the property name, and the value (another object) that was removed, and just kept these in a list, like so:
public class RemovedReference
{
public object Object;
public string PropertyName;
public object Value;
}
There's probably a smarter structure to accomplish this; you could use a PropertyInfo object for example instead of a string, and you might cache the type to cheapen the second round of reflection.
This is an old question but still relevant with Entity Framework 6.2.0. My solution is three-fold:
Do NOT set the MainChildId column as HasDatabaseGeneratedOption(Computed) (this blocks you from updating it later)
Use a Trigger to update the Parent when I'm inserting both records simultaneously (this isn't a problem if the parent already exists and I'm just adding a new child, so be sure the Trigger accounts for this somehow - was easy in my case)
After calling ctx.SaveChanges(), also be sure to call ctx.Entry(myParentEntity).Reload() to get any updates to the MainChildId column from the Trigger (EF won't automatically pick these up).
In my code below, Thing is the parent and ThingInstance is the child and has these requirements:
Whenever a Thing (parent) is inserted, a ThingInstance (child) should also be inserted and set as the Thing's CurrentInstance (main child).
Other ThingInstances (children) may be added to a Thing (parent) with or without becoming the CurrentInstance (main child)
This resulted in the following design:
* EF Consumer must insert both records but leave CurrentInstanceId as null but be sure to set ThingInstance.Thing to the parent.
* Trigger will detect if a ThingInstance.Thing.CurrentInstanceId is null. If so, then it will update it to the ThingInstance.Id.
* EF Consumer must reload/refetch the data to view any updates by the trigger.
* Two round-trips are still necessary but only one atomic call to ctx.SaveChanges is necessary and I don't have to deal with manual rollbacks.
* I do have an extra trigger to manage, and there might be a more efficient way to do it than what I've done here with a cursor, but I'll never be doing this in a volume where performance will matter.
Database:
(Sorry, not tested this script - just generated it from my DB and put it here due to being in a hurry. You should definitely be able to get the important bits out of here.)
CREATE TABLE [dbo].[Thing](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[Something] [nvarchar](255) NOT NULL,
[CurrentInstanceId] [bigint] NULL,
CONSTRAINT [PK_Thing] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[ThingInstance](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[ThingId] [bigint] NOT NULL,
[SomethingElse] [nvarchar](255) NOT NULL,
CONSTRAINT [PK_ThingInstance] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Thing] WITH CHECK ADD CONSTRAINT [FK_Thing_ThingInstance] FOREIGN KEY([CurrentInstanceId])
REFERENCES [dbo].[ThingInstance] ([Id])
GO
ALTER TABLE [dbo].[Thing] CHECK CONSTRAINT [FK_Thing_ThingInstance]
GO
ALTER TABLE [dbo].[ThingInstance] WITH CHECK ADD CONSTRAINT [FK_ThingInstance_Thing] FOREIGN KEY([ThingId])
REFERENCES [dbo].[Thing] ([Id])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[ThingInstance] CHECK CONSTRAINT [FK_ThingInstance_Thing]
GO
CREATE TRIGGER [dbo].[TR_ThingInstance_Insert]
ON [dbo].[ThingInstance]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #thingId bigint;
DECLARE #instanceId bigint;
declare cur CURSOR LOCAL for
select Id, ThingId from INSERTED
open cur
fetch next from cur into #instanceId, #thingId
while ##FETCH_STATUS = 0 BEGIN
DECLARE #CurrentInstanceId bigint = NULL;
SELECT #CurrentInstanceId=CurrentInstanceId FROM Thing WHERE Id=#thingId
IF #CurrentInstanceId IS NULL
BEGIN
UPDATE Thing SET CurrentInstanceId=#instanceId WHERE Id=#thingId
END
fetch next from cur into #instanceId, #thingId
END
close cur
deallocate cur
END
GO
ALTER TABLE [dbo].[ThingInstance] ENABLE TRIGGER [TR_ThingInstance_Insert]
GO
C# Inserts:
public Thing Inserts(long currentId, string something)
{
using (var ctx = new MyContext())
{
Thing dbThing;
ThingInstance instance;
if (currentId > 0)
{
dbThing = ctx.Things
.Include(t => t.CurrentInstance)
.Single(t => t.Id == currentId);
instance = dbThing.CurrentInstance;
}
else
{
dbThing = new Thing();
instance = new ThingInstance
{
Thing = dbThing,
SomethingElse = "asdf"
};
ctx.ThingInstances.Add(instance);
}
dbThing.Something = something;
ctx.SaveChanges();
ctx.Entry(dbThing).Reload();
return dbThing;
}
}
C# New Child:
public Thing AddInstance(long thingId)
{
using (var ctx = new MyContext())
{
var dbThing = ctx.Things
.Include(t => t.CurrentInstance)
.Single(t => t.Id == thingId);
dbThing.CurrentInstance = new ThingInstance { SomethingElse = "qwerty", ThingId = dbThing.Id };
ctx.SaveChanges(); // Reload not necessary here
return dbThing;
}
}