Create Mock Custom Metadata with Child Relationship Query - salesforce

I have a Controller class on which I execute a SOQL query to Custom Metadata Type records.
The SOQL query also contains a child relationship query (Master-Detail relationship).
I need to write a test with mock custom metadata records
#AuraEnabled(cacheable=true)
public static List<Response> getLeadMetadataValues() {
List<Lead_Business_Status__mdt> leadBusinessStatusList = [
SELECT Id, Label, DeveloperName, Index__c,
(SELECT Id, Label, DeveloperName, Reason_Status_Api_Name__c FROM Lead_Reason_Status__r)
FROM Lead_Business_Status__mdt ORDER BY Index__c ASC
];
List<Response> resList = new List<Response>();
if (Test.isRunningTest()) {
leadBusinessStatusList = new List<Lead_Business_Status__mdt>();
leadBusinessStatusList.add(createMock());
}
for (Lead_Business_Status__mdt bs : leadBusinessStatusList) {
Response res = new Response();
res.Id = bs.Id;
res.businessStatusLabel = bs.Label;
res.businessStatusDevName = bs.DeveloperName;
res.index = bs.Index__c;
for (Lead_Reason_Status__mdt rs : bs.Lead_Reason_Status__r) {
ReasonStatus rsObj = new ReasonStatus();
rsObj.Id = rs.Id;
rsObj.reasonStatusLabel = rs.Label;
rsObj.reasonStatusDevName = rs.DeveloperName;
rsObj.fieldApiName = rs.Reason_Status_Api_Name__c;
res.reasonStatusList.add(rsObj);
}
resList.add(res);
}
return resList;
}
I use Test.isRunningTest() to populate the leadBusinessStatusList with the mock data.
I am able to create a mock object for the Master record: Lead_Business_Status__mdt and Detail record: Lead_Reason_Status__mdt. However, I wasn't able to add the Detail record to the related list: Lead_Reason_Status__r
private static Lead_Business_Status__mdt createMock() {
String reasonStatusStr = '{"Label":"Transfer to Queue", "DeveloperName":"Transfer_to_Queue", "Reason_Status_Api_Name__c":"Transfer_to_Queue"}';
Lead_Reason_Status__mdt reasonStatusObj = (Lead_Reason_Status__mdt) System.JSON.deserialize(reasonStatusStr, Lead_Reason_Status__mdt.class);
System.debug('Lead_Reason_Status__mdt: ' + reasonStatusObj);
String businessStatusStr = '{"Label":"Wrong Lead", "DeveloperName":"Wrong_Lead", "Index__c":"1"}';
Lead_Business_Status__mdt businessStatusObj = (Lead_Business_Status__mdt) System.JSON.deserialize(businessStatusStr, Lead_Business_Status__mdt.class);
return businessStatusObj;
}
The test is covered except the inner for loop of the Lead_Reason_Status__mdt.
How can I create a mock object with populating the child relationship list?

Can you try use JSON.deserialize method to setup these metadata records.
List<Lead_Business_Status__mdt> leadBusinessStatusList = (List< Lead_Business_Status__mdt >) JSON.deserialize( '[{"Id": "xoid914011599", "Label": "test", "DeveloperName": "test","Reason_Status_Api_Name__c": "test"}, {"Id": "xoid9140115992","Label":"test2","DeveloperName": "test2","Reason_Status_Api_Name__c": "test2"}]', List<Lead_Business_Status__mdt>.class );

Related

Salesforce updating metadata record using apex

'I am trying to update a salesforce metadata record via Apex. here is my code:
Metadata.DeployContainer mdContainer = new Metadata.DeployContainer();
for(Omni_Routing_Skillset__mdt md: omnimetadata) {
Metadata.CustomMetadata customMetadata = new Metadata.CustomMetadata();
customMetadata.fullName = md.DeveloperName; //custom metadata name
customMetadata.Label = md.MasterLabel;
Metadata.CustomMetadataValue customField1 = new Metadata.CustomMetadataValue(); //the values you're changing/updating
customField1.field = 'Omni_Routing_Skillset__mdt.Skill_Level__c'; //the custom field API Name that you're wanting to insert/update a value of
customField1.value = skillsAndValues.get(md.MasterLabel);
customMetadata.values.add(customField1);//add the changes to list of changes to be deployed
mdContainer.addMetadata(customMetadata);
System.debug('customMetadata: ' + customMetadata);
}
//MetadataDeploy callback = new MetadataDeploy();
Id jobId = Metadata.Operations.enqueueDeployment(mdContainer, null);
This kicks off the deployment but i get the following error:
**Must specify the name in the CustomMetadataType.CustomMetadata format, Current Name: Team_2_SEP, Required Delimiter: .**
I am not sure how to fix this, can anyone please advise?
Thanks!
The name would be Omni_Routing_Skillset__mdt.Team_2_SEP you're only passing in Team_2_SEP.
You can reference this method:
public static void updateExisitingMetadatRecord() {
List<Metadata_Creditional__mdt> metadatList = [SELECT Id, DeveloperName,
MasterLabel FROM Metadata_Creditional__mdt WHERE DeveloperName='MyTest'];
Metadata.CustomMetadata metadataRec = new Metadata.CustomMetadata();
metadataRec.fullName =
'Metadata_Creditional__mdt.'+metadatList[0].DeveloperName;
metadataRec.label = metadatList[0].MasterLabel;
//provide the value for the fields and add it to custom metadata instance
Metadata.CustomMetadataValue totalPurchasetoUpdate = new
Metadata.CustomMetadataValue();
totalPurchasetoUpdate.field = 'Secret_Key__c';
totalPurchasetoUpdate.value = 'Change Secreet Value';
metadataRec.values.add(totalPurchasetoUpdate);
Metadata.DeployContainer mdContainer = new Metadata.DeployContainer();
mdContainer.addMetadata(metadataRec);
Metadata.Operations.enqueueDeployment(mdContainer, null);
}

How to test contentdocumentlink trigger for Salesforce Prod deployment

I am trying to deploy a trigger to prod on salesforce. I was hoping someone could help me with an example of tests for this trigger.
Here is my trigger. It does its purpose, which is to update a bool field when a new contentNote (or anything of content type) that then has collateral effects through process builder.
trigger NewNote on ContentDocumentLink (before insert) {
Set<Id> setParentId = new Set<Id>();
List<Client_Relationships__c> crlst = new List<Client_Relationships__c>();
for (ContentDocumentLink cdl : trigger.new ) {
setParentId.add(cdl.LinkedEntityId);
}
crlst = [select Id , newNote__c from Client_Relationships__c where Id IN :setParentId];
For(Client_Relationships__c e : crlst)
{
e.newNote__c = True;
}
update crlst;
}
The trigger you wrote can be more efficient by omitting the SOQL query as seen below:
trigger NewNote on ContentDocumentLink (before insert) {
List<Client_Relationships__c> crlst = new List<Client_Relationships__c>();
for (ContentDocumentLink cdl : trigger.new ) {
if(cdl.LinkedEntityId.getSObjectType().getDescribe().getName() == 'Client_Relationships__c'){
crlst.add(
new Client_Relationships__c(
Id = cdl.LinkedEntityId,
newNote__c = true
)
);
}
}
update crlst;
}
The best practice would be to add your code to a handler or utility class and to only have one trigger per object. The name of this trigger could be changed to "ContentDocumentLinkTrigger" if you adopt that practice.
The test class for that trigger is below. I could not test the compilation because I don't have the same custom object.
#IsTest
private class ContentDocumentLinkTriggerTest {
#TestSetup
static void setupTest() {
insert new ContentVersion(
Title = 'Test_Document.txt',
VersionData = Blob.valueOf('This is my file body.'),
SharingPrivacy = 'N',
SharingOption = 'A',
Origin = 'H',
PathOnClient = '/Test_Document.txt'
);
List<Client_Relationships__c> relationships = new List<Client_Relationships__c>();
for(Integer i = 0; i < 300; i++){
relationships.add(
new Client_Relationships__c(
//add required field names and values
)
);
}
insert relationships;
}
static testMethod void testInsertTrigger() {
//prepare data
List<ContentVersion> contentVersions = new List<ContentVersion>([
SELECT Id, ContentDocumentId FROM ContentVersion
]);
System.assertNotEquals(0, contentVersions.size(), 'ContentVersion records should have been retrieved');
List<Client_Relationships__c> relationships = getAllClientRelationships();
System.assertNotEquals(0, relationships.size(), 'Client Relationship records should have been retrieved.');
List<ContentDocumentLink> documentLinks = new List<ContentDocumentLink>();
for(Integer i = 0; i < 252; i++){
documentLinks.add(
new ContentDocumentLink(
ContentDocumentId = contentVersions[0].ContentDocumentId,
LinkedEntityId = relationships[i].Id,
ShareType = 'I'
)
);
}
//test functionality
Test.startTest();
insert documentLinks;
Test.stopTest();
//assert expected results
List<Client_Relationships__c> relationshipsAfterProcessing = getAllClientRelationships();
for(Client_Relationships__c relationship : relationshipsAfterProcessing){
System.assert(relationship.newNote__c, 'The newNote__c field value should be true.');
}
}
private static List<Client_Relationships__c> getAllClientRelationships(){
return new List<Client_Relationships__c>([
SELECT Id, newNote__c FROM Client_Relationship__c
]);
}
}
For setting up test data, it is helpful to have a utility class that centralizes the creation of well-formed records. This is extremely useful when your code base gets large and a validation rule affects the insertion of new data in many test classes. With a centralized method, the inserted data only needs to be altered once.

MongoDB Compass returns all rows when I run a filter

I am trying to run a filter in MongoDB Compass and it returns all rows instead of the row that I am looking for. I can run the filter on example databases that are similar to my database without any problem.
https://i.stack.imgur.com/IBivJ.png
Here is the code that I am using to add records and select from them.
public class NoSQLDataAccess
{
// Create an instance of data factory
public NoSQLDataFactory noSQLDataFactory;
public List<dynamic> DocumentDetails { get; set; }
private IMongoCollection<dynamic> collection;
private BsonDocument bsonDocument = new BsonDocument();
public NoSQLDataAccess() { }
public void TestNoSQL()
{
MongoClient client;
IMongoDatabase database;
string connectionString = ConfigurationManager.AppSettings["NoSQLConnectionString"];
client = new MongoClient(connectionString);
database = client.GetDatabase("TestDatabase");
collection = database.GetCollection<dynamic>("TestCollection");
// Insert
List<Layer> layers = new List<Layer>();
layers.Add(new Layer { LayerId = 117368, Description = "BOOTHLAYER" });
layers.Add(new Layer { LayerId = 117369, Description = "DRAWINGLAYER" });
layers.Add(new Layer { LayerId = 117370, Description = "LAYER3" });
List<Element> elements = new List<Element>();
elements.Add(new Element { ElementId = 9250122, Type = "polyline" });
elements.Add(new Element { ElementId = 9250123, Type = "polyline" });
List<dynamic> documentDetails = new List<dynamic>();
documentDetails.Add(new DrawingDTO { Layers = layers, Elements = elements });
collection.InsertMany(documentDetails);
List<FilterDetails> filterDetails = new List<FilterDetails>();
filterDetails.Add(new FilterDetails { Type = "layers.id", Value = "117368" });
foreach (FilterDetails detail in filterDetails)
{
bsonDocument.Add(new BsonElement(detail.Type, detail.Value));
}
List<dynamic> results = collection.Find(bsonDocument.ToBsonDocument()).ToList();
}
}
I have been able to get the result I need with MongoDB shell but I have not been able to replicate the results in C#.
Here is the solution in MongoDB shell:
db.TestCollection.find({"layers.id": 117368}, {_id:0, layers: {$elemMatch: {id: 117368}}}).pretty();
I have found a post that is similar to my question that works for them. The C# code that I attached is how I will access it after I get it working properly. I use MongoDB Compass to test finds/inserts/updates/deletes.
Retrieve only the queried element in an object array in MongoDB collection

NHibernate Convert query to async query

I'm looking at async-ifying some of our existing code. Unfortunately my experience with NHibernate is lacking. Most of the NHibernate stuff has been easy, considering NHibernate 5 has a lot of support for async. I am, however, stuck.
Originally, we do something like this using our Dependency Injection:
private readonly IRepository repository;
public MovieRepository(IRepository repository)
{
this.repository = repository;
}
public Movie Get(int id)
{
return (from movie in repository.Query<Movie>()
select new Movie
{
ID = movie.ID,
Title = movie.Title,
Genre = new Genre
{
ID = movie.Genre.ID,
Name = movie.Genre.Name,
},
MaleLead = movie.MaleLead,
FemaleLead = movie.FemaleLead,
}).FirstOrDefault();
}
//Repository Query method in Repository.cs
public IQueryable<TEntity> Query<TEntity>() where TEntity : OurEntity
{
session = session.OpenSession();
return from entity in session.Query<TEntity>() select entity;
}
This works great for our current uses. We write things this way to maintain control over our queries, especially related to more complex objects, ensuring we get back exactly what we need.
I've tried a few things, like making the Query method return a Task< List< TEntity>> and using the ToListAsync() method, however because I am returning it as that kind of list I cannot query on it.
I'm sure I've missed something. If anyone can help me out, I would appreciate it.
You need to use FirstOrDefaultAsync in this case.
public async Task<Movie> Get(int id)
{
return await (from movie in repository.Query<Movie>()
select new Movie
{
ID = movie.ID,
Title = movie.Title,
Genre = new Genre
{
ID = movie.Genre.ID,
Name = movie.Genre.Name,
},
MaleLead = movie.MaleLead,
FemaleLead = movie.FemaleLead,
}).FirstOrDefaultAsync();
}
Add this using statement to your file
using NHibernate.Linq;
Then you can change your method to
public async Task<Movie> Get(int id)
{
return await (from movie in repository.Query<Movie>()
select new Movie
{
ID = movie.ID,
Title = movie.Title,
Genre = new Genre
{
ID = movie.Genre.ID,
Name = movie.Genre.Name,
},
MaleLead = movie.MaleLead,
FemaleLead = movie.FemaleLead,
}).FirstOrDefaultAsync();
}
NB: This is only available from NHibernate 5
Addendum:
The code you have in Repository.cs can be simplified to something like this:
//Repository Query method in Repository.cs
public IQueryable<TEntity> Query<TEntity>() where TEntity : OurEntity
{
//session = session.OpenSession(); //this is obviously wrong, but it's beside the point
var session = sessionFactory.OpenSession();
return session.Query<TEntity>(); //the fix
}

Get back #html.dropdownlist ID value for database insert / update in Webmatrix

I have build some dropdown lists using the LINK to Objects method and #html.dropdownlist Webmatrix helper. This works fine.
I want to know how to pass / store the selected value in my database table.
Build of items list in code section
var titlesData = db.Query("SELECT TitleId, Name FROM Titles ORDER BY Name");
titlesListItems = titlesData.Select(i => new SelectListItem {
Value = i.TitleId.ToString(),
Text = i.Name,
Selected = i.TitleId == providerData.TitleId ? true : false
});
HTML markup section:
#Html.DropDownList("titlesCombo","-- Veuillez sélectionner -- ",titlesListItems)
Database update command (see the ???):
db.Execute("UPDATE Providers SET TitleId=#0 WHERE ProviderId=#1",???,providerId)
The method I used for now is to create another variable:
var titleId = "";
if (!IsPost) {
titleId = providerData.TitleId.ToString(); //providerData stores the SQL query result
}
if (IsPost) {
var titleId = Request.Form[TitleID]
db.Execute("UPDATE Providers SET TitleId=#0 WHERE ProviderId=#1",titleId,providerId)
}
Unfortunately, data doesn't get updated
From what I can see, you haven't referenced rightly the DropDownList helper in your code.
Try with the following code:
var titleId = "";
if (!IsPost) {
titleId = providerData.TitleId.ToString();
}
if (IsPost) {
titleId = Request.Form["titlesCombo"];
db.Execute("UPDATE Providers SET TitleId=#0 WHERE ProviderId=#1",titleId,providerId);
}

Resources