Create my own API - salesforce

I use in my force.com application Apex Classes, and many of them have the same structure, I want to make an API to reuse it after.
For exaple, these are two classes :
//first class
public class insererActAct{
public List<Activites_actuelles__c> accts {get; set;}
public insererActAct(ApexPages.StandardController controller){
accts = new List<Activites_actuelles__c>();
accts.add(new Activites_actuelles__c());
}
public void addrow(){
accts.add(new Activites_actuelles__c());
}
public PageReference deleteRow(){
if (accts.size()>1)
{
accts.remove(accts.size()-1);
}
return null;
}
public PageReference save()
{
insert accts;
Assure__c theParent = new Assure__c(id=accts[0].Activites_actuelles__c);
PageReference acctPage = new ApexPages.StandardController(theParent).view();
acctPage.setRedirect(true);
return acctPage;
}
}
//second class
public class insererEnfants{
public List<Enfants__c> accts {get; set;}
public insererEnfants(ApexPages.StandardController controller){
accts = new List<Enfants__c>();
accts.add(new Enfants__c());
}
public void addrow(){
accts.add(new Enfants__c());
}
public PageReference deleteRow(){
if (accts.size()>1)
{
accts.remove(accts.size()-1);
}
return null;
}
public PageReference save()
{
insert accts;
Assure__c theParent = new Assure__c(id=accts[0].Parent__c);
PageReference acctPage = new ApexPages.StandardController(theParent).view();
acctPage.setRedirect(true);
return acctPage;
}
}
Can any one tell me it is possible or not, if yes, how can I do this, please ?

Do you mean you want to write code that works for different kinds of objects, rather than stating the type of object in the code?
It is possible to do this, by declaring your sObject variables with the sObject type, e.g, instead of
public List<Activites_actuelles__c> accts {get; set;}
you would put
public List<sObject> sObjects{get; set;}
and by referencing fields using get and put, e.g. instead of
Account theAccount = new Account();
theAccount.name = 'Fred';
you would put
sObject theSObject = new SObject();
theSObject.put('name', 'Fred');
I've not tried using code like this in a controller extension, but in theory since you can pass in any standard controller you ought to be OK.
You will need to think about how to create the parent object inside the save method, because you will need to pass in what type you want to create. It's quite complicated but it is possible to take in a string representing the object type (e.g. 'Account') and create a new object of that type:
Schema.getGlobalDescribe().get('Account').newSObject()
will get you a new Account. So you could replace 'Account' with any type passed in as a parameter.
For more information look up Dynamic Apex, Dynamic SOQL and Dynamic DML in the documentation.
A word of warning: Passing around object types and field names as strings means that the compiler will not know those types are mentioned in the code. So if you try and delete a custom object or rename a field, salesforce will not warn you that the object or field is in use and will allow you to do the deletion.
Another word of warning: Although this allows code reuse and that is a benefit, you may find it is not worth it. I avoid writing dynamic apex unless I absolutely have to. It is far more complex than ordinary apex and it is therefore difficult to debug and maitain, especially if someone other than yourself has to maintain it.

Related

Flow: Use new type for variable?

I have a simple new class X which holds some results of a callout to an external system.
In a flow I need a variable of type X. Is there any way to declare a variable of that new type in a flow?
My new class is:
public class FooCalloutResult {
public Boolean success;
public Map<Id, Boolean> results;
public List<String> messages;
public FooCalloutResult() {
success = false;
results = new Map<Id, Boolean>();
messages = new List<String>();
}
}
If you want to get some data in a flow from an apex class you need to have an Process Invocable method - this is done by adding the #InvocableMethod annotation.
Example:
global class lookUpAccountAnnotation {
#InvocableMethod
public static List<String> getAccountIds(List<String> names) {
List<Id> accountIds = new List<Id>();
List<Account> accounts = [SELECT Id FROM Account WHERE Name in :names];
for (Account account : accounts) {
accountIds.add(account.Id);
}
return accountIds;
}
}
With this annotation the class will appear in your list of available elements in the Flow and you need to put the Input and Output that will go into it.
Depending on what kind of operation you want to do you might need to use the Process.plugin interface instead. Please check this article to see which option supports what kind of data to decide on what you need - https://help.salesforce.com/articleView?id=vpm_designer_elements_apex.htm&type=5

How to use Dapper's SqlBuilder?

I can't find any documentation or examples I can follow to use the SqlBuilder class.
I need to generate sql queries dynamically and I found this class. Would this be the best option?
the best place to start is to checkout the dapper source code from its github repo and have a look at the SqlBuilder code. The SqlBuilder class is only a 200 lines or so and you should be able to make an informed choice on whether it is right for your needed.
An other option is to build your own. I personally went down this route as it made sense. Dapper maps select querys directly to a class if you name your class properties the same as your database or add an attribute such as displayName to map from you can use reflection to get the property names. Put there names and values into a dictionary and you can genarate sql fairly easy from there.
here is something to get you started:
first an example class that you can pass to your sqlbuilder.
public class Foo
{
public Foo()
{
TableName = "Foo";
}
public string TableName { get; set; }
[DisplayName("name")]
public string Name { get; set; }
[SearchField("fooId")]
public int Id { get; set; }
}
This is fairly basic. Idea behind the DisplayName attribute is you can separate the properties out that you want to include in your auto generation. in this case TableName does not have a DisplayName attribute so will not be picked up by the next class. however you can manually use it when generating your sql to get your table name.
public Dictionary<string, object> GetPropertyDictionary()
{
var propDictionary = new Dictionary<string, object>();
var passedType = this.GetType();
foreach (var propertyInfo in passedType.GetProperties())
{
var isDef = Attribute.IsDefined(propertyInfo, typeof(DisplayNameAttribute));
if (isDef)
{
var value = propertyInfo.GetValue(this, null);
if (value != null)
{
var displayNameAttribute =
(DisplayNameAttribute)
Attribute.GetCustomAttribute(propertyInfo, typeof(DisplayNameAttribute));
var displayName = displayNameAttribute.DisplayName;
propDictionary.Add(displayName, value);
}
}
}
return propDictionary;
}
This method looks at the properties for its class and if they are not null and have a displayname attribute will add them to a dictionary with the displayname value as the string component.
This method is designed to work as part of the model class and would need to be modified to work from a separate helper class. Personally I have it and all my other sql generation methods in a Base class that all my models inherit from.
once you have the values in the dictionary you can use this to dynamically generate sql based on the model you pass in. and you can also use it to populate your dapper DynamicParamaters for use with paramiterized sql.
I hope this helps put you on the right path to solving your problems.

Salesforce (SFDC) - public, static, global keywords - use one list for entire class?

I'm having a hard understanding using public, static, and global keywords with my variables and methods.
Below is a snippet of my code. What I'm trying to do is upon page load, in my constructor create a Set of accountIDs that the user has access to (8-33 this is working). This set will be used to filter queries used in later methods.
What I'm finding is that public pageReference runSearch() has access to 'terrAccSet', but the public static List getsearchAccounts does not have access to it.
If I change it to public static Set terrAccSet, I don't get data in either of the system.debugs - what can I do?
global with sharing class MyClass {
public static List<FRM_Metrics_gne__c> accountSearchGmap {get; set;}
public Set<Id> terrAccSet;
public List<String> terrIdList;
//Constructor
public MyClass() {
terrAccSet = new Set<Id>();
terrIdList = new List<String>();
Set<Id> grpIdSet = new Set<Id>();
Id uid = '00570000001R95e'; //member of TWO territories
//UserTerritory Utid = [SELECT TerritoryId FROM UserTerritory where UserId = :userInfo.getUserId()];
List<UserTerritory> Utid = [SELECT TerritoryId FROM UserTerritory where UserId =: uid ];
for(UserTerritory usrTerr: Utid){
terrIdList.add(usrTerr.TerritoryId);
}
List<Group> grp = [Select Id from Group where RelatedID IN :terrIdList];
for (Group eachgroupd : grp ){
grpIdset.add(eachgroupd.Id);
}
List<AccountShare> accountidList = [SELECT AccountId,UserOrGroupId FROM AccountShare where UserOrGroupId in :grpIdset];
//all accounst that the user has access according to territory hiearchy
for(AccountShare eachas:accountidList ){
terrAccSet.add(eachas.AccountId);
}
}
public PageReference runSearch() {
//Has Data
system.debug('**terrAccSet runSearch** '+terrAccSet);
}
public static List<Custom_Object__c> getsearchAccounts(String multiSearchString) {
//terrAccSet variable is missing
system.debug('**terrAccSet getSearchAccounts** '+terrAccSet);
//logic
return accountSearchGmap;
}
}
Below is a snippet of my code. What I'm trying to do is upon page load, in my constructor create a Set of accountIDs that the user has access to (8-33 this is working). This set will be used to filter queries used in later methods.
This set should be an instance property, not static.
Use static when you want to create a method that does not affect the state of a controller or class, eg. a text parser-text in text out.
You should make the class Global if you want to create a package and make your class available outside your package so that other Apex code can invoke it, or if your class will create webService or REST methods to be exposed.
Public should be used to expose properties to the VisualForce pages that will consume the properties. Otherwise, use Private methods and properties for controller side only processing.
public static List getsearchAccounts(String multiSearchString) {
//terrAccSet variable is missing
system.debug('terrAccSet getSearchAccounts '+terrAccSet);
//logic
return accountSearchGmap;
}
This method should not be static because it accesses an instance property (it reads state).
Simple rule of thumb, if it is a visualforce page + controller, you shouldn't need anything static to do your normal work of querying the database and returning data to the page.

c# returning arrays via properties

Id like to firstly apologise for what may appear to be a stupid question but im confused regarding the following.
Im writting a class library which will not be running on the UI thread. Inside the CL i need an array which im going populate with data received from a stored procedure call. I then need to pass this data back to the UI thread via an event.
Originally i was going to write the following.
public class ColumnInformation
{
public string[] columnHeaderNames;
public string[] columnDataTypes;
}
but im pretty sure that would be frowned upon and i instead should be using properties.
public class ColumnInformation
{
public string[] columnHeaderNames {get; set;}
public string[] columnDataTypes {get; set;}
}
but then i came across the following.
MSDN
so am i correct in assuming that i should actually declare this as follows:
public class ColumnInformation
{
private string[] _columnHeaderNames;
public Names(string[] headerNames)
{
_columnHeaderNames = headerNames;
}
public string[] GetNames()
{
// Need to return a clone of the array so that consumers
// of this library cannot change its contents
return (string[])_columnHeaderNames.Clone();
}
}
Thanks for your time.
If your concern is the guideline CA1819: Properties should not return arrays,
It will be same whether you are exposing Array as a Public Field, or Property (making readonly does not matter here). Once your original Array is exposed, its content can be modified.
To avoid this, as the link suggest, make Field private, and return Clone from the Getter.
However major concern is that there may be multiple copies of your array if retrieved many times. It is not good for performance and synchronization.
Better solution is ReadOnlyCollection.
Using ReadOnlyCollection, you can expose the collection as read only which cannot be modified. Also any changes to underlying collection will be reflected.

RIA Services SP2 Function Complex type not visible in Object Context

I am struggling with returning a complex type from my services layer. It doesnt seem to be accessible from my object context.
This is the query in the service layer. All compiling fine.
public IQueryable<USP_GetPostsByThreadID_Result> uspGetPostsByThreadID(int ThreadID)
{
return this.ObjectContext.USP_GetPostsByThreadID(ThreadID).AsQueryable();
}
When I try and call it from my client, the ForumContext is not seeing it. I checked the client generated file and nothing similar is being generated. Help!!!
The name of your method may not meet the expected convention for queries. Try one or both of the following:
Add the [Query] attribute
Rename the method to GetUspPostsByThreadID
Result:
[System.ServiceModel.DomainServices.Server.Query]
public IQueryable<USP_GetPostsByThreadID_Result> GetUspPostsByThreadID(int ThreadID)
{
return this.ObjectContext.USP_GetPostsByThreadID(ThreadID).AsQueryable();
}
Its very common to have a stored procedure returning data from multiple tables. The return type doesn't fit well under any of the Entity Types(Tables). Therefore if we define Complex Type as the return collection of objects from Stored Procedure invocation, it becomes quite a powerful tool for the developer.
Following these steps I have achieved successfully the configuration of complex type on a sample AdventureWorks database.
1. Refer the picture and ensure the Stored procedure and function import is done.
2. Add the Domain Service name it as AdventureDomainService.
3. Now its time to define the tell the RIA services framework to identify my Complex Type as Entity Type. To be able to do this, we need to identify a [Key] DataAnnotation. Entity types provide data structure to the application's data model and by design, each entity type is required to define a unique entity key. We can define key on one property or a set of properties in metadata class file AdventureDomainService.metadata.cs
First define the class then add MetadatatypeAttribute like :
[MetadataTypeAttribute(typeof(CTEmployeeManagers.CTEmployeeManagersMetadata))]
public partial class CTEmployeeManagers
{
internal sealed class CTEmployeeManagersMetadata
{
private CTEmployeeManagersMetadata() { }
[Key]
public int EmployeeID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int ManagerID { get; set; }
public string ManagerFirstName { get; set; }
public string ManagerLastName { get; set; }
}
}
Define the Domain service method to return the collection of objects/entities for populating the Silverlight Grid or any other data consuming controls.
public IQueryable<CTEmployeeManagers> GetEmployeeManagers(int empId)
{
return this.ObjectContext.GetEmployeeManagers(empId).AsQueryable();
}
We define IQueryable if we are to fetch the records from datasources like SQL, whereas we define IEnumerable if we are to fetch the records from in memory collections,dictionaty,arrays.lists, etc.
Compile the server side to generate the client proxy.
In the Silverlight side open the MainPage.xaml or wherever the datagrid is put, then add following namespaces :
using System.ServiceModel.DomainServices.Client;
using SLBusinessApplication.Web;
using SLBusinessApplication.Web.Services;
..
Load the data and display:
public partial class MyPage : Page
{
AdventureDomainContext ctx = new AdventureDomainContext();
public MyPage()
{
InitializeComponent();
LoadOperation loadOp = this.ctx.Load(this.ctx.GetEmployeeManagersQuery(29));
myGrid.ItemsSource = loadOp.Entities;
}
// Executes when the user navigates to this page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
}
}
That is all that is needed to do.
It has to be part of an entity. Complex types cannot be returned by themselves

Resources