Apex code-how to get the data of campaign Members from Subquery - salesforce

I am trying to display four fields on my VF page Name, Status from (Campaign Members) and Subject and Last Modified Date from (Activity History) Object.I am not able to fetch the Name and Status fields from Campaign Members.
Can anyone please tell me How to get the Name and Status fields from Campaign Members.Below is my Controller code.
public with sharing class CampaignView {
public Campaign camp {get; set; }
public List<MemberWrapper> lMemberWrappers {get; set;}
public DateTime startDate {get; set;}
public CampaignView(ApexPages.StandardController controller) {
camp = (Campaign)controller.getRecord();
lMemberWrappers = new List<MemberWrapper>();
getCampaignMembers();
startDate = null;
for (Campaign c : [Select ID, (SELECT Id, CampaignId, Status FROM CampaignMembers where CampaignId = :camp.Id) FROM campaign WHERE id = :camp.Id ]) {
for (Lead ld : CampaignMembers) {
for (ActivityHistory ah : ld.getSObjects('ActivityHistories')) {
lMemberWrappers.add(new MemberWrapper(ld.Name, ah.Subject, ah.LastModifiedDate, ld.CampaignMembers.get(0).Status));
}
}
}
}
private List<Lead> CampaignMembers;
public List<Lead> getCampaignMembers() {
CampaignMembers = [Select Id, Name, Phone, MobilePhone, Email, LastModifiedDate, (Select id, Campaign.Name, Contact.Phone, Lead.FirstName, Lead.LastName, Lead.Name, LeadID, ContactID, Lead.Phone, Lead.Email, Lastmodifieddate, Lead.LastmodifiedDate, Status, CampaignId, Campign_ID__c, Lead.MobilePhone From CampaignMembers where CampaignId = :camp.Id ),
(Select Subject, Id, lastModifiedDate From ActivityHistories order by LastModifiedDate DESC LIMIT 1 )
From Lead where Id IN(select LeadId from campaignMember where campaignId = :camp.Id ) ];
return CampaignMembers;
}
public class MemberWrapper {
public Object Status {get; set;}
public String Name {get; set;}
public String Subject {get; set;}
public Datetime LastActivityHistory {get; set;}
public MemberWrapper(String Name, String Subject, Datetime LastActivityHistory, Object Status ) {
this.Name = Name;
this.Subject = Subject;
this.LastActivityHistory = LastActivityHistory;
this.Status = Status;
}
}
}

This will take you more than one query because of the ActivityHistory requirement. There are four levels of relationships in play here: Campaign -> CampaignMember -> Lead -> ActivityHistory, so you cannot perform this using just sub-queries.
The following code should get you the info you need:
Set<Id> leadIds = new Set<Id>();
List<Campaign> campaignList = [Select ID, (SELECT Id, Status, LeadId FROM CampaignMembers) FROM campaign WHERE id = :camp.Id ];
for (Campaign c : campaignList) {
for (CampaignMember cm : c.CampaignMembers) {
leadIds.add(cm.LeadId);
}
}
Map<Id, Lead> leadMap = new Map<Id, Lead>([Select Id, Name, (Select Subject, LastModifiedDate from ActivityHistories Order By LastModifiedDate DESC limit 1) From Lead Where Id IN :leadIds]);
for (Campaign c : campaignList) {
for (CampaignMember cm : c.CampaignMembers) {
Lead ld = leadMap.get(cm.LeadId);
if (ld.ActivityHistories.size() > 0) {
ActivityHistory ah = ld.ActivityHistories[0];
lMemberWrappers.add(new MemberWrapper(ld.Name, ah.Subject, ah.LastModifiedDate, cm.Status));
}
}
}
I just skipped creating the MemberWrapper if there were no activities, but you could change it to just put blank values if you wish.

Related

FIFO inventory systems - Converting T-SQL to Linq

Please how do I convert this T-SQL statement to Linq or lambda? Trying to implement FIFO inventory systems
DECLARE #TakenQty int;
SET #TakenQty = 90;
WITH cte AS
(
SELECT *, SUM(qty) OVER (ORDER BY accept_date, id ASC) AS CumQty
FROM RS_GIN_Master
WHERE qty > 0
)
SELECT TOP ((SELECT COUNT(*) FROM cte WHERE CumQty <#TakenQty)+1)
batch_no, accept_date,
CASE
WHEN CumQty < #TakenQty THEN qty
ELSE #TakenQty - (CumQty - Qty)
END AS TakenOut
FROM
cte
Table definition
The final result is like this
Please how do I convert this T-SQL statement to Linq or lambda?
You don't.
LINQ and SQL share many common query operators, but LINQ has nothing equivalent to
SUM(qty) OVER (ORDER BY accept_date, id ASC) RANGE BETWEEN UNBOUNDED PRECEEDING AND CURRENT ROW
Which is what that expression is shorthand for. And it certainly has no way to write an expression that EF could translate to this TSQL.
So you leave it in TSQL. And if you must have an implementation outside of SQL Server, you start from scratch.
I was able to resolve this
void Main()
{
var data = new List<History>()
{
new History(1,1,20,DateTime.Now.AddDays(-24),"001"),
new History(2,1,2,DateTime.Now.AddDays(-23),"002"),
new History(3,2,2,DateTime.Now.AddDays(-24),"001"),
new History(3,1,29,DateTime.Now.AddDays(-22),"003"),
new History(3,1,50,DateTime.Now.AddDays(-21),"004"),
};
var demo = Results(data, 30);
demo.Dump(); //note using LinqPad
}
public class History
{
public History(int id, int stockId, int qty, DateTime date, string batchNumber)
{
Id = id;
StockId = stockId;
Qty = qty;
Date = date;
BatchNumber = batchNumber;
}
public int Id { get; set; }
public int StockId { get; set; }
public int Qty { get; set; }
public string BatchNumber { get; set; }
public DateTime Date { get; set; }
}
public static List<Result> Results(List<History> data, int takenQty)
{
var runningTotal = 0;
var result = data.Where(p => p.StockId == 1).OrderBy(p => p.Date).ThenBy(p => p.Id)
.Select(x => new
{
x.Id,
x.Date,
x.BatchNumber,
x.Qty,
x.StockId,
CumQty = (runningTotal = runningTotal + x.Qty)
}).ToList();
var query = result.Select(x => new Result
{
StockId =x.StockId,
Id = x.Id,
BatchNumber = x.BatchNumber,
Qty = x.Qty,
Used = x.CumQty < takenQty ? x.Qty : takenQty - (x.CumQty - x.Qty)
}).Take((result.Count(p => p.CumQty < takenQty)) + 1).ToList();
return query;
}
public class Result
{
public int Id { get; set; }
public int StockId { get; set; }
public int Qty { get; set; }
public string BatchNumber { get; set; }
public int Used { get; set; }
public int Left => Qty - Used;
}
And the final output

Getting dupicate agent names

Here am using map ,not abled to understand how to solve the duplicate name,i want one agent name against number of payments(child of opp)
how do I get unique names of users
public class First_Pay_ClearRates_Controller {
#AuraEnabled
public static Map<Id,User> fetchUsers() {
// List<User> userList= [SELECT Id, Name FROM User WHERE Profile.Name = 'Sales' LIMIT 20];
Map<Id,User> userMap= new Map<Id,User>([SELECT Id, Name FROM User WHERE Profile.Name = 'Sales' LIMIT 20]);
return userMap;
}
#AuraEnabled
public static List<Opportunity> getOpps(Map<Id,User> usrMap){
Map<Id,List<Opportunity>> oppMap = new Map<Id,List<Opportunity>>();
List<Opportunity> oppList = new List<Opportunity>();
List<Payments__c> payList= new List<Payments__c>();
List<Payments__c> payList1= new List<Payments__c>();
// prev key Agent_Name_User__c
// AND First_Payment_Date__c=THIS_MONTH
for(Opportunity o: [SELECT Id,First_Payment_Date__c,OwnerId,Owner.Name ,of_Payments_Made__c,PaymentsCounter__c,CollectedPaymentCount__c,First_Client_Payment_Collected_Date__c From Opportunity WHERE OwnerId IN: usrMap.keyset() AND First_Payment_Date__c!=null LIMIT 20]){
if(!oppMap.containsKey(o.OwnerId)){
oppMap.put(o.OwnerId,new List<Opportunity>());
}
o.PaymentsCounter__c=0;
o.CollectedPaymentCount__c=0;
//AND Due_Date__c=THIS_MONTH
for(Payments__c p :[Select Id,Opportunity__c,Payment_Collected__c,Due_Date__c FROM Payments__c WHERE Opportunity__c =: o.Id ]){
if(!p.Payment_Collected__c){
payList.add(p);
o.PaymentsCounter__c= payList.size();
}else if(p.Payment_Collected__c){
payList1.add(p);
o.CollectedPaymentCount__c= payList1.size();
}
}
oppList.add(o);
oppMap.put(o.OwnerId,oppList);
}
return oppList;
}

ASP.NET Core & Entity Framework Core : one-to-many relation and navigation properties

I am using ASP.NET Core and Entity Framework Core, and controller API for my react app database connect.
I have 4 classes Customer, Product, Store and Sales. The Customer, Product and Store table have a one-to-many relation with sales.
Sales class
public class Sales
{
[Key]
public int SalesId { get; set; }
public int ProductId { get; set; }
public int CustomerId { get; set; }
public int StoreId { get; set; }
[DataType(DataType.Date)]
public string DateSold { get; set; }
public Product Product { get; set; }
public Customer Customer { get; set; }
public Store Store { get; set; }
}
Customer class
public class Customer
{
[Key]
public int CustomerId { get; set; }
[Column(TypeName = "nvarchar(100)")]
public string Name { get; set; }
[Column(TypeName = "nvarchar(100)")]
public string Address { get; set; }
public IList<Sales> Sales { get; set; }
}
The other Product and store are same as customer class.
I run the migration command but the database was not created and command run successful so I created database and then I run the update-database which created all the tables in database.
If I add navigation properties to table will it fetch Sales record with Customer, Product and Store record as per ID in sales record.
I want to fetch sales record and in the sales table there is customer, product and store ID. How can I fetch their record?
My tables look like this:
I want to fetch sales record and in the sales table there is customer, product and store ID. How can I fetch their record?
Based on your model design , you could use Include method for loading related data like below:
Controller
[HttpGet]
public async Task<ActionResult<object>> GetSales()
{
var salesdata = await _context.Sales
.Include(s => s.Customer)
.Include(s => s.Product)
.Include(s => s.Store)
.Select(s => new
{
salesId = s.SalesId,
dateSold = s.DateSold,
customer = new
{
name = s.Customer.Name,
address = s.Customer.Address
},
product = new
{
name = s.Product.Name,
price = s.Product.Price
},
store = new
{
name = s.Store.Name,
address = s.Store.Address
}
})
.ToListAsync();
return salesdata;
}
For query syntax , you could use the Join in EF Core for Complex Query Operators
var data = from s in _context.Sales
join cu in _context.Customer on s.CustomerId equals cu.CustomerId
join p in _context.Product on s.ProductId equals p.ProductId
join st in _context.Store on s.StoreId equals st.StoreId
select new
{
salesId = s.SalesId,
dateSold = s.DateSold,
customer = new
{
name = s.Customer.Name,
address = s.Customer.Address
},
product = new
{
name = s.Product.Name,
price = s.Product.Price
},
store = new
{
name = s.Store.Name,
address = s.Store.Address
}
};
return await data.ToListAsync();
Result

Multi-mapping to the same table twice

How do you use Dapper's Multi-Mapping feature on two fields using the same table? i.e ClientInfo has two Address objects.
public class ClientInfo
{
public Guid Id => Guid.NewGuid();
public string FirstName { get; set; }
public string LastName { get; set; }
public Address PostalAddress { get; set; }
public Address BillingAddress { get; set; }
public int ContactNumber { get; set; }
}
public class Address
{
public Guid Id = Guid.NewGuid();
public string FirstLine { get; set; }
public string SecondLine { get; set; }
public string Town { get; set; }
public string PostCode { get; set; }
}
Tables
Relational - Address.Id used in ClientInfo.PostalAddress / BillingAddress
tbl.Address
|Id|FirstLine|SecondLine|Town|PostCode
tbl.ClientInfo
|Id|FirstName|LastName|PostalAddress|BillingAddress|etc..
Current implementation
Results only in all but PostalAddress being mapped.
var sql = #"select * from ClientInfo c left join Address as a on a.Id = c.PostalAddress left join Address as ad on ad.Id = c.BillingAddress";
var clients = connection.Query<ClientInfo, Address, Address, ClientInfo>(
sql,
(client, postal, billing) =>
{
client.PostalAddress = postal;
client.BillingAddress = billing;
return client;
},
splitOn: "PostalAddress,BillingAddress")
.Distinct()
.ToList();
return clients;
The splitOn parameter tells Dapper when/where to start mapping the next object, so you need to ensure that your SQL query returns the information in the correct order. Right now, you return 2 guids for PostalAddress and BillingAddress. Dapper doesn't know how to map them both.
select * from ... join ... will result in the Address data ordered AFTER the ClientInfo.PostalAddress and ClientInfo.BillingAddress columns.
Try: SELECT c.Id, c.FirstName, c.LastName, c.ContactNumber, a.*, ad.* FROM ClientInfo c LEFT JOIN Address AS a ON a.Id = c.PostalAddress JOIN Address AS ad ON ad.Id = c.BillingAddress
As you can see, removing the * effectively excludes the PostalAddress and BillingAddress guids from the results and we can now now splitOn: "Id,Id".
You will of course not have to provide the GUIDs in the select statement, this is just for the test to work.
[Test]
public void TestAbcd()
{
using (var dbConnection = new SqlConnection(_connectionString))
{
const string sql = #"WITH ClientInfo AS (
SELECT * FROM (
VALUES (#ci1, #adr1, #adr2), (#ci1, #adr3, #adr4)
) AS a (Id, PostalAddress, BillingAddress)
),
Address AS (
SELECT * FROM (
VALUES
(#adr1), (#adr2), (#adr3), (#adr4)
) AS a (Id)
)
select * from ClientInfo c left join Address as a on a.Id = c.PostalAddress left join Address as ad on ad.Id = c.BillingAddress";
dbConnection.Open();
var clients = dbConnection.Query<ClientInfo, Address, Address, ClientInfo>(
sql,
(client, postal, billing) =>
{
client.PostalAddress = postal;
client.BillingAddress = billing;
return client;
},
splitOn: "PostalAddress,BillingAddress", param: new {
ci1 = Guid.NewGuid(),
ci2 = Guid.NewGuid(),
adr1 = Guid.NewGuid(),
adr2 = Guid.NewGuid(),
adr3 = Guid.NewGuid(),
adr4 = Guid.NewGuid()
})
.Distinct()
.ToList();
}
}

Dapper one to many losing Id in the many

Given the following two entities
public class Customer
{
public Customer()
{
Orders = new List<Orders>();
}
public int CustomerId { get; set; }
public string CustomerName { get; set; }
public List<Orders> Orders { get; set; }
}
and
public class Orders
{
public int OrderId { get; set; }
public int CustomerId { get; set; }
public int Quantity { get; set; }
public string OrderDescription { get; set; }
}
And the following code
string sql = #"
select c.CustomerId, c.CustomerName, o.OrderId as OrderId, o.CustomerId, o.Quantity, o.OrderDescription
from Customer c
join Orders o on c.CustomerId = o.CustomerId";
var customers = new List<Customer>();
Customer currentCustomer = null;
var c = connection.Query<Customer, Orders, Customer>(
sql, (customer, order) => {
if (currentCustomer == null || currentCustomer.CustomerId != customer.CustomerId)
{
customers.Add(customer);
currentCustomer = customer;
}
currentCustomer.Orders.Add(order);
return currentCustomer;
}, splitOn: "CustomerId, OrderId");
When I inspect customers the OrderId is always 0. As in customers.Orders[0].OrderId is zero, for all of them. Now I suppose it is me doing something wrong, but I can't figure out what. The strange SQL you see above is my attempts to try and force the OrderId to work.

Resources