Debugging Call Stack Exceeded C# Backend - c#

I have a get route a that is going to get data of wells and well tests, when I execute the call on swagger, it will take awhile and then give me a call stack error. My problem is I cant figure out how to get a log or idea of where this is happening. The best I have been able to do so far is use point breaks at every step to see how far it gets. I've gotten to the controller route so I know that its grabbing the data just fine, my understanding is that it now has the data, and should use the view model to match and display the data. I have gone through about 100 data samples in the view model and it seems fine but there is 2400 units, all with 5 arrays inside of them. However it will simply error out with no message. Any ideas of whats going on or how to debug this? Is there a way in VS Code so see a better log of something like this or another tool that will do that will help in this situation?
** Service Code: **
public async Task<IEnumerable<SapDispatchViewModel>> GetDispatchDeliveryForSap()
{
var result = await _dispatchRepo.GetDispatchDeliveryForSap(TenantId);
var view = new List<SapDispatchViewModel>();
foreach (SapDispatch row in result)
{
var sapView = _mapper.Map<SapDispatch, SapDispatchViewModel>(row);
var items = await _dispatchItemRepo.GetDispatchItemsByTruckForSap(row.DispatchTruckId);
var viewItems = _mapper.Map<IEnumerable<SapDispatchItem>, IEnumerable<SapDispatchItemViewModel>>(items);
sapView.Items = viewItems;
view.Add(sapView);
}
return view;
}
** It calls this GetDispatchDeliveryForSap first: **
public async Task<IEnumerable<SapDispatch>> GetDispatchDeliveryForSap(string TenantId)
{
string deliveryType = "Delivery";
//resort to raw SQL to assist with performance improvements
FormattableString sql = $#"
WITH cte_latestStatus AS
( SELECT * FROM (
SELECT
s.TenantId,
s.DispatchId,
s.DispatchHeaderId,
s.RequestedArrival,
s.EstimatedArrival,
s.Status,
u.FirstName + ' ' + u.LastName UserName,
s.CreateDate StatusChangeDate,
row_number() over(partition by DispatchHeaderId order by CreateDate desc) as rn
FROM
DispatchStatus s
JOIN AspNetUsers u on s.CreateUserId = u.Id
) t
WHERE t.rn = 1
)
select w.wellid,
w.wellname,
wo.ErpId,
wc.ContractorName + ' ' + w.RigNumber Rig,
w.CountyParish County,
w.State,
d.type DispatchType,
u.LastName + ',' + u.FirstName OrderedBy,
ds.RequestedArrival RequestedDate,
dt.DriverName,
dt.SwamperName,
dt.TicketNumber,
dt.DispatchTruckId
from well w
join Dispatch d on w.wellid = d.DestinationWellId
join cte_latestStatus ds on d.DispatchId = ds.DispatchId and d.HeaderId = ds.DispatchHeaderId
join DispatchTruck dt on d.DispatchId = dt.DispatchId
join AspNetUsers u on d.CreateUserId = u.Id
left join WellContractorRef wcr on w.WellId = wcr.WellId
left join Contractor wc on wcr.ContractorId = wc.ContractorId
left join WellOperatorRef wor on w.WellId = wor.WellId
left join Operator wo on wor.OperatorId = wo.OperatorId
--join DispatchItem di on dt.DispatchTruckId = di.DispatchTruckId
where d.TenantId = {TenantId}
and d.type = {deliveryType}
and (ds.Status = 'Completed' or dt.status = 'Completed')
order by w.wellname"
;
var result = await context.SapDispatches.FromSqlInterpolated(sql).AsNoTracking().ToListAsync();
return result;
}
}
}
** Then maps via the view model to create the list: **
namespace Mudman.Model.ViewModels
{
public class SapDispatchViewModel
{
public string WellId { get; set; }
public string WellName { get; set; }
public string ErpId { get; set; }
public string Rig { get; set; }
public string County { get; set; }
public string State { get; set; }
public string DispatchType { get; set; }
public string OrderedBy { get; set; }
public DateTime? RequestedDate { get; set; }
public string DriverName { get; set; }
public string SwamperName { get; set; }
public long? TicketNumber { get; set; }
public IEnumerable<SapDispatchItemViewModel> Items { get; set; }
}
public class SapDispatchItemViewModel
{
public string ErpId { get; set; }
public Decimal? Price { get; set; }
public Decimal? Quantity { get; set; }
public string Size { get; set; }
public string Unit { get; set; }
}
}
** From there, it runs the foreach on the GetDispatchItemsForTruckSap: **
public async Task<IEnumerable<SapDispatchItem>> GetDispatchItemsByTruckForSap(string dispatchTruckId)
{
//resort to raw SQL to assist with performance improvements
FormattableString sql = $#"
WITH cte as (
SELECT
COALESCE(ProductId, ExpenseId) AS SalesItemID,
Price,
Quantity
FROM DispatchItem
WHERE DispatchTruckId = {dispatchTruckId}
)
SELECT si.ErpId,
cte.Price,
cte.Quantity,
si.Size,
si.Unit
FROM SalesItem si
INNER JOIN cte on cte.SalesItemID = si.SalesItemId"
;
var result = await context.SapDispatchItems.FromSqlInterpolated(sql).AsNoTracking().ToListAsync();
return result;
}
}
}
** Maps with the Item View Model: **
public class SapDispatchItemViewModel
{
public string ErpId { get; set; }
public Decimal? Price { get; set; }
public Decimal? Quantity { get; set; }
public string Size { get; set; }
public string Unit { get; set; }
}
}
** Then it will hit the return and thats where it will error out.
Also, here is what the callstack is looking like when you hit that return.

Try turning on Break When Thrown on Common Language Runtime Exceptions and it should break at the error:

Related

EF Core recursive folder structure serialized incorrectly

I'm trying to utilize EF Core to execute a Raw Sql statement and "serialize" it back to a recursive object structure.
My data looks like this
Folders -
Requests -
//Folder.cs
[Table("PsRequestFolder")]
public class PsRequestFolder : IWorkSpaceNode
{
[Key]
public int FolderId { get; set; }
public string FolderName = "";
public PsWorkSpace? FolderWorkSpace { get; set; }
public PsRequestFolder? ParentFolder { get; set; }
public List<PsHttpRequest> Requests { get; set; } = new List<PsHttpRequest>();
public List<PsRequestFolder> Folders { get; set; } = new List<PsRequestFolder>();
...
// Request.cs
[Table("PsHttpRequest")]
public class PsHttpRequest : IWorkSpaceNode
{
[Key]
public int RequestId { get; set; }
public string Url = "";
public string RequestName = "";
public PsWorkSpace RequestWorkSpace{ get; set; }
public int PsRequestFolderFolderId { get; set; }
public PsRequestFolder ContainingFolder { get; set; }
...
I'm executing this sql statement by calling FromSqlRaw
ws.RequestFolders = await context.RequestFolders.FromSqlRaw(
#"
WITH cte_ws AS (
SELECT
FolderId,
FolderName,
ParentFolderFolderId,
FolderWorkSpaceWorkSpaceId,
p1.*
FROM PsRequestFolder
LEFT JOIN PsHttpRequest AS p1 ON PsRequestFolder.FolderId = p1.PsRequestFolderFolderId
WHERE ParentFolderFolderId IS NULL
UNION ALL
SELECT
e.FolderId,
e.FolderName,
e.ParentFolderFolderId,
e.FolderWorkSpaceWorkSpaceId,
p1.*
FROM PsRequestFolder as e
LEFT JOIN PsHttpRequest AS p1 ON e.FolderId = p1.PsRequestFolderFolderId
INNER JOIN cte_ws o
on o.FolderId= e.ParentFolderFolderId
)
SELECT * FROM cte_ws;
"
).ToListAsync();
I would expect to get back something that looks like
One
RequestOne
RequestTwo
Two
Six
Eight
Nine
RequestThree
Seven
Three
Four
Five
Instead I get something like this back
Not sure why some of the things that should be nested underneath others aren't being nested as well as why the requests under folder Nine don't come through at all, as well folder Nine and some others being written twice to the list
The raw sql output just running it against the db is -
Any assistance is greatly appreciated!

Sql query combining results

I have the following:
void Main()
{
// I need to get the below query, but with the newest comment date as well of each post.
// Gives me all the posts by the member
var member_id = 1139;
var query = (from posts in Ctm_Forum_Posts
join category in Ctm_Forum_Categories on posts.FK_Categori_ID equals category.Id
where posts.Archieved == false
&& posts.Deleted == false
&& posts.FK_Member_ID == member_id
select new ForumPostModel(){
Id = posts.Id,
BodyText = posts.BodyText,
Summary = posts.Summary,
Title = posts.Title,
Created = posts.Created,
Updated = posts.Updated,
CategoryName = category.Title,
});
// this gives the newest comment date (registration_timestamp) from a specific post with id = 1
var NewestCommentDate = (from comments in Ctm_Comments
join posts in Ctm_Forum_Posts on comments.Page_ID equals posts.Id
where posts.Id == 1 && comments.Deleted == false
orderby comments.Reqistration_timestamp descending
select comments.Reqistration_timestamp).FirstOrDefault();
}
// Model of the result.
public class ForumPostModel{
public int Id { get; set; }
public string Title { get; set; }
public string BodyText { get; set; }
public string Summary { get; set; }
public DateTime Created { get; set; }
public DateTime Updated { get; set; }
public string CategoryName { get; set; }
public DateTime LatestCommentTime { get; set; }
}
Right now the two queries work, but my problem is the performance sucks,, so im trying to combine the results into a single query, so my load time will be much less.
I tried searching about unions, but have been unable to figure it out.

Join few tables without repeat same data

I have got two tables,
Feedback Table and Steps Table. Each feedback has multiple Steps. If i use LINQ with join method it returnd same number of step items (obj) in FeedbackViewModel and each contains only 1 single step. I mean ery similar to SQL return.
FeedbackViewModel[0]{FeedbackID = 1,FeedbackName="NameA", Steps{Step1}}
FeedbackViewModel[1]{FeedbackID = 1,FeedbackName="NameA", Steps{Step2}}
FeedbackViewModel[2]{FeedbackID = 1,FeedbackName="NameA", Steps{Step3}}
BUT I only want one FeedbackViewModel object which contains many Steps.
FeedbackViewModel[0]{FeedbackID = 1,FeedbackName="NameA", Steps{Step1, Step2, Step 3 etc..}
I can do it by foreach Loop but it doesn't look professional.
Thanks for help
public class Feedback
{
public int FeedbackID { get; set; }
public string FeedbackName { get; set; }
}
public class StepModel
{
public int StepID { get; set; }
public int FeedbackID { get; set; } = 0;
public int StepNumber { get; set; }
public string StepDetail { get; set; }
public virtual Feedback FeedBack { get; set; }
}
public class FeedbackViewMODEL
{
public int FeedbackID { get; set; }
public string FeedbackName { get; set; }
public List<StepModel> Steps { get; set; }
}
var quote = from feed in FeedBacks
join stp in StePs on feed.FeedbackID equals stp.FeedbackID
where feed.FeedbackID == id
select new FeedbackViewMODEL
{
Step = stp;
}
Using the LINQ group join will combine all the matching steps:
var quote = from feed in FeedBacks
where feed.FeedbackID == id
join stp in StePs on feed.FeedbackID equals stp.FeedbackID into stpj
select new FeedbackViewMODEL {
FeedbackID = feed.FeedbackID,
FeedbackName = feed.FeedbackName,
Steps = stpj.ToList()
};
I think you should left outer join.
from feed in Feedbacks
join stp in steps on feed.FeedbackID equal stp.FeedbackID into result
where feed.FeedBackID == id and result.DefaultIfEmpty()

Add data to a list insde a list where item in the prerent list

I would like to select a where statement that adds items to a list where only product codes match. I have it so it gets all of the products sold in the sale but I would like there were statement to get only products in this sale.
PS: This is really hard to explain
Model
public class userSales
{
public string Name { get; set; }
public string UserName { get; set; }
public int Sale_Id { get; set; }
public int CostumerID { get; set; }
public string Sale_Date { get; set; }
public string Paid { get; set; }
public Nullable<int> Sale_Cost { get; set; }
public string Discount_Code { get; set; }
public List<SaleProduct> saleProductsList { get; set; }
}
public class SaleProduct
{
public int SaleID { get; set; }
public string ProductCode { get; set; }
public int ProductCount { get; set; }
public string Image_Path { get; set; }
public string Shoot_Date { get; set; }
public string Shoot_Info { get; set; }
}
Linq statement where I'm having trouble:
var test = (from _ClientData in db.ClientDatas
join _salesInfo in db.Sales_Infoes
on _ClientData.CostumerID
equals _salesInfo.CostumerID
where _ClientData.UserName == _userName
select new userSales()
{
CostumerID = _ClientData.CostumerID,
Name = _ClientData.Name,
UserName = _ClientData.UserName,
Sale_Id = _salesInfo.Sale_Id, // This is the item i would like to use in my were statement
Sale_Date = _salesInfo.Sale_Date,
Sale_Cost = _salesInfo.Sale_Cost,
Discount_Code = _salesInfo.Discount_Code,
Paid = _salesInfo.Paid,
// Problem here
saleProductsList = db.SaleProducts.Where()
}).ToList();
Got to this based on the answer:
var reult = db.ClientDatas.Where(a => a.UserName == _userName)
.Join(db.Sales_Infoes,
a => a.CostumerID,
b => b.CostumerID,
(a, b) => new userSales()
{
CostumerID = a.CostumerID,
Discount_Code = b.Discount_Code,
Sale_Cost = b.Sale_Cost,
Sale_Id= b.Sale_Id,
Name = a.Name,
Sale_Date = b.Sale_Date,
UserName = a.UserName,
Paid = b.Paid,
saleProductsList = db.SaleProducts.Where(c => c.SaleID == b.Sale_Id).ToList()
}).ToList();
You're not looking for a where, you're looking for a join. Where filters the results on a single table, join intersects two tables which is actually what you want here.
var result = db.Sales_Infoes.Where(x => x.UserName == _userName)
.Join(db.ClientDatas,
x => x.Sale_Id,
y => y.Sale_id,
(x, y) => new userSales() {
// x is SalesInfo obj y is ClientDatas obj do assignement here
Name = y.Name,
Sale_Date = y.Sale_date
}).ToList();
Just fyi I haven't had a chance to test that but it's the basic idea. You don't need a select like in your statement because the last argument I'm passing into join is the lambda (x, y) => ... in that case x and y are the current row from each table (that we've gotten from applying our where to the user sales table then joining those results into the salesproduct table) so whatever projections you want to do occur there. The other two method args above that are the telling join which fields to compare, it's the 'key selector' lambda expression for each table.

LINQ to XML join issue

I'm having real trouble with a join that I am trying to perform on two separate XML files.
I have two classes that describe each object that I extract from the XML files, they are
public class XMLCustomers
{
public String CustomerID { get; set; }
public String ContactName { get; set; }
}
and
public class XMLOrders
{
public String OrderID { get; set; }
public String CustomerID { get; set; }
public String OrderDate { get; set; }
public String ShippedDate { get; set; }
public String Freight { get; set; }
public String ShipName { get; set; }
public String ShipCity { get; set; }
public String ShipCountry { get; set; }
}
And my last class stores the join that I perform on the two sets of data.
public class PostXMLJoinOrder
{
public String OrderID { get; set;}
public String ContactName { get; set;}
public String OrderDate { get; set;}
public String ShippedDate { get; set;}
public String Freight { get; set;}
public String ShipName { get; set;}
public String ShipCity { get; set;}
public String ShipCountry { get; set;}
}
Finally these are my two methods that load the information from the XML files and the third method performs a join and stores the information in a IEnumerable
public IEnumerable<XMLCustomers> LoadXMLCustomers() {
var custs = from x in XElement.Load(System.Web.HttpContext.Current.Server.MapPath(#"~\App_Data\XCustomers.xml")).Elements()
select new XMLCustomers
{
ContactName = x.Attribute("ContactName").Value,
CustomerID = x.Attribute("CustomerID").Value
};
int size = custs.Count();
return custs;
}
public IEnumerable<XMLOrders> LoadXMLOrders() {
var ords = from x in XElement.Load(System.Web.HttpContext.Current.Server.MapPath(#"~\App_Data\XOrders.xml")).Elements()
select new XMLOrders
{
OrderID = x.Attribute("ContactName").Value,
CustomerID = x.Attribute("CustomerID").Value,
OrderDate = x.Attribute("OrderDate").Value,
ShippedDate = x.Attribute("ShippedDate").Value,
Freight = x.Attribute("Freight").Value,
ShipName = x.Attribute("ShipName").Value,
ShipCity = x.Attribute("ShipCity").Value,
ShipCountry = x.Attribute("ShipCountry").Value
};
int size = ords.Count();
return ords;
}
public IEnumerable<PostXMLJoinOrder> LoadPostXMLJoinOrders() {
var joinQuery = from customer in LoadXMLCustomers()
from orders in LoadXMLOrders()
where customer.CustomerID == orders.CustomerID
select new PostXMLJoinOrder
{
OrderID = orders.OrderID,
ContactName = customer.ContactName,
OrderDate = orders.OrderDate,
ShippedDate = orders.ShippedDate,
Freight = orders.Freight,
ShipName = orders.ShipName,
ShipCity = orders.ShipCity,
ShipCountry = orders.ShipCountry
};
return joinQuery;
}
I have tested the amount of items returned from my LINQ and it continues to be 0;
I have double checked everything being loaded in from the files but I cant seem to get my head around at which point its going wrong.
Edit:
its a loading issue. the XML files are definitely stored under the correct App_Data folder. But when the individial LoadXMLCustomers() is running Im getting a NullReferenceException at the part where the lINQ statement selects and creates the new Loaded Customer object.
I have already made sure the build for the XML documents are content and copyToOutputDirectory is set to if newer
this is the Exception & Also the var value is null so its definitely not loading for some reason:
SOLVED: The lesson I learnt here is that you need to pay close attention to your XML and data. If some of your XML data has empty values, then you need to account by making sure the select statement can handle it.
Above I had the code
select new XMLOrders
{
OrderID = x.Attribute("ContactName").Value,
CustomerID = x.Attribute("CustomerID").Value,
OrderDate = x.Attribute("OrderDate").Value,
ShippedDate = x.Attribute("ShippedDate").Value,
Freight = x.Attribute("Freight").Value,
ShipName = x.Attribute("ShipName").Value,
ShipCity = x.Attribute("ShipCity").Value,
ShipCountry = x.Attribute("ShipCountry").Value
};
Which really should have included casts to string values so if there is empty data is "" not throwing a null exception.
Secondly I should have been getting the Element values not the Attribute values.
select new XMLOrders
{
OrderID = (string)x.Element("OrderID").Value,
CustomerID = (string)x.Element("CustomerID").Value,
OrderDate = (string)x.Element("OrderDate").Value,
ShippedDate = (string)x.Element("ShippedDate").Value,
Freight = (string)x.Element("Freight").Value,
ShipName = (string)x.Element("ShipName").Value,
ShipCity = (string)x.Element("ShipCity").Value,
ShipCountry = (string)x.Element("ShipCountry").Value
};
Have you tried not to use join but just:
from customer in LoadXMLCustomers()
from order in LoadXMLOrders()
where customer.CustomerID = order.CustomerID
select new PostXMLJoinOrder
...
Just notice that in such query LoadXMLOrders() can be called once again for each customer. So pre-save it first.
Also don't forget to materialize queries calling ToArray()/ToList().

Categories

Resources