Select clause null - c#

I am currently using
your = from p in (toSelect)
select new
{
last = p.Last,
current = p.CurrentPlayer,
seats = from s in (p.Seated)
select new
{
UID = s.UID,
buyin = s.BuyIn
}
}
p.Seated is an array, how can I pass null every time s.UID is unset? I know about "where" but I was to know which seats are free (e.g. null)
Hope this is clear enough.

You could try this:
your = from p in (toSelect)
select new
{
last = p.Last,
current = p.CurrentPlayer,
seats = p.Seated.Select(s => s.UID != null
? new
{
UID = s.UID,
buyin = s.BuyIn
}
: null;
}

Replace your expression that you're assigning to seats with:
seats = p.Seated.Select(s => s != null ? new { UID = s.UID, buyin = s.BuyIn } : null)
Hope this is clear enough.
I'll be honest. It's not clear enough. Is s.UID a nullable type and that's what we need to compare to null?

Related

Some values in LINQ Query Statement aren't saved correctly to class with subsonic 3

I am developing a MVC 3 Application which uses Subsonic 3 for accessing the database.
My Problem is, i don't understand why the Enum "GlobalType" is not being written into the property.
Everytime i check, the value is 0 instead of "One".
The "Name" property contains the "DateCreated" value.
The "DateCreated" property contains a new DateTime instance.
No other fields, as far as i'm aware of, are doing this.
There is no logic inside of the ViewItemModel, it's just a class with properties.
If i add them after this method manually, everything works.
Maybe someone encountered something similar with subsonic (if it even is subsonic itself, maybe i'm making a mistake)?
I have this method in the Backend:
public IEnumerable<ViewItemModel> LoadView(int registratorId)
{
var itemModel = from item in _itemQuery
join header in _headerQuery on item.HeaderID equals header.ID
where header.RegistratorID == registratorId && !(from hidden in _headerHiddenQuery where hidden.ItemID == item.ID && hidden.Type == GlobalType.One && hidden.RegistratorID == registratorId select hidden.ID).Any()
orderby item.ID descending
select new ViewItemModel()
{
Type = GlobalType.One,
ID = item.ID,
Name = header.Name,
DateCreated = header.DateCreated,
TypeOfTransport = header.TypeOfTransport,
TransportType = item.TransportType,
Count = (from subItems in _subItemQuery where subItems.ItemID == item.ID select subItems.ID).Count(),
// For Status
IsArchived = header.IsArchived,
IsCanceled = header.IsCanceled,
Process = header.Process,
End = header.End,
IsPublished = header.IsPublished,
OpenFrom = header.OpenFrom,
OpenTill = header.OpenTill,
IsNextStarted = header.IsNextStarted
};
return itemModel.ToList();
}
Update:
The GlobalType enum looks like this
public enum GlobalType
{
One = 1,
Two = 2,
Individual = 3
}
If i add them manually, i changed the return statement for this:
var result = itemModel.ToList();
foreach (var item in result)
{
var headerId = _itemQuery.Where(it => it.ID == item.ID).Select(it => it.HeaderID).FirstOrDefault();
var created = _itemQuery.Where(it => it.ID == item.ID).Select(it => it.DateCreated).FirstOrDefault();
var name = _headerQuery.Where(it => it.ID == headerId).Select(it => it.Name).FirstOrDefault();
item.AnnouncementType = GlobalType.One;
item.Name = name;
item.DateCreated = created;
}
return result;
try sample code:
public int enum GlobalType
{
One = 1,
Two = 2,
Individual = 3
}
//enum value Convert to int or other data type using casting
item.AnnouncementType = (int) GlobalType.One;
//Suppose if condition using
if((GlobalType)item.AnnouncementType==GlobalType.One)
{
//your code
}
Thanks to DaveParsons comment, i managed to create a workaround.
In this case, the code will have to iterate twice through the list of found elements, but won't load the entire table into memory.
Since there is a bug (throwing exception) with creating an anonymous object containing multiple classes like so:
select new { item, header, subItems }
I managed to get all the data needed, by manually assigning what i need like so:
public IEnumerable<ViewItemModel> LoadView(int registratorId)
{
var itemModel = from item in _itemQuery
join header in _headerQuery on item.AnnouncementHeaderID equals header.ID
where header.RegistratorID == registratorId && !(from hidden in _headerHiddenQuery where hidden.ItemID == item.ID && hidden.Type == GlobalType.One && hidden.RegistratorID == registratorId select hidden.ID).Any()
orderby item.ID descending
select new {
Type = GlobalType.One,
ID = item.ID,
Name = header.Name,
DateCreated = header.DateCreated,
TypeOfTransport = header.TypeOfTransport,
TransportType = item.TransportType,
Count = (from subItems in _subItemQuery where subItems.ItemID == item.ID select subItems.ID).Count(),
// For Status
IsArchived = header.IsArchived,
IsCanceled = header.IsCanceled,
Process = header.Process,
End = header.End,
IsPublished = header.IsPublished,
OpenFrom = header.OpenFrom,
OpenTill = header.OpenTill,
IsNextStarted = header.IsNextStarted
};
return itemModel
.ToList()
.Select(it => new ViewItemModel() {
Type = it.Type,
ID = it.ID,
Name = it.Name,
DateCreated = it.DateCreated,
TypeOfTransport = it.TypeOfTransport,
TransportType = it.TransportType,
Count = it.Count,
// For Status
IsArchived = it.IsArchived,
IsCanceled = it.IsCanceled,
Process = it.Process,
End = it.End,
IsPublished = it.IsPublished,
OpenFrom = it.OpenFrom,
OpenTill = it.OpenTill,
IsNextStarted = it.IsNextStarted
})
.ToList();
}
Notice: The return value of the query is an anonymous object with every single necessary field declared.
After the database returned all fields with the same name as in the database (model), we then have to force execution with ".ToList()" or something similar (deferred execution?).
Since the data is now in memory, we can assign the values from the anonymous object to the original class that was intended for this purpose.
I am sure there is a more reliable way using reflection, but this is what i have come up with.

Linq calling a method in select statement very slow

I am trying to find if there is a way to call a method from within my linq select statement to build a list of objects that doesn't dramatically slow it down. The reason behind this is that I also want to call the same method when trying to get only one of the objects and do not want to have to maintain both versions (i.e. if I have another field added to the object or want to render one of the fields differently I will not have to change it in multiple places).
In the example below, TEST 1 runs over 100 times faster than TEST 2:
// Start timer
var timer = new Stopwatch();
timer.Start();
var test = (from job in dc.Jobs
where !job.archived
select new JobExtended()
{
JobId = job.jobId,
NodeId = job.nodeId,
JobName = job.name != string.Empty ? job.name : "TBC",
Salary = job.salary,
RecruiterId = job.fkRecruiterId,
RecruiterNodeId = job.JobRecruiter != null ? job.JobRecruiter.recruiterNodeId : null,
RecruiterName = job.JobRecruiter != null ? job.JobRecruiter.name : string.Empty,
LocationId = job.fkLocationId,
Location = job.refJobLocation != null ? job.refJobLocation.jobLocation : "",
ContractTypeId = job.fkContractTypeId,
ContractType = job.refJobContractType != null ? job.refJobContractType.contractType : "",
CategoryId = job.fkCategoryId,
Category = job.refJobCategory != null ? job.refJobCategory.category : "",
ClosingDate = job.closingDate,
Featured = job.featured,
JobOfTheWeek = job.jobOfTheWeek,
PublishedDate = job.publishedDate,
Url = "/jobs/" + job.name.Replace(" ", "-").Replace("&", "and").Replace("'", "") + (job.fkLocationId.HasValue ? "-in-" + job.refJobLocation.jobLocation.Replace(" ", "-").Replace("&", "and").Replace("'", "") : "") + "-jn" + job.jobId,
CreatedOn = job.createdOnDate,
PrintWidth = job.printWidth,
PrintHeight = job.printHeight,
UntilFilled = (job.untilFilled != null && job.untilFilled.Value),
AdvertCost = job.advertCost,
DatesToShow = job.relJobDates.Where(x => x.fkJobId == job.jobId).Select(x => x.date).ToList(),
IsParentJob = job.relLinkedJobs != null && job.relLinkedJobs.Any(x => x.fkParentJobId == job.jobId),
IsAlternateWeekJob = job.alternateWeek != null && job.alternateWeek.Value,
Archived = job.archived,
LastModifiedDate = job.lastModifiedDate,
RecruiterContactDetails = job.recruiterContactDetails
}).ToList();
// Stop timer
timer.Stop();
// Output info
litTest.Text = "TEST 1 in " + timer.Elapsed.TotalSeconds + " seconds<br/>";
//Start timer
timer = new Stopwatch();
timer.Start();
var test2 = (from job in dc.Jobs
where !job.archived
select GetJobDetails(job)).ToList();
//Stop timer
timer.Stop();
//Output info
litTest.Text += "TEST 2 in " + timer.Elapsed.TotalSeconds + " seconds<br/>";
This is the method that TEST 2 is calling which should be creating the same object that is being returned in TEST 1:
public static JobExtended GetJobDetails(Data.Job job)
{
return new JobExtended()
{
JobId = job.jobId,
NodeId = job.nodeId,
JobName = job.name != string.Empty ? job.name : "TBC",
Salary = job.salary,
RecruiterId = job.fkRecruiterId,
RecruiterNodeId = job.JobRecruiter != null ? job.JobRecruiter.recruiterNodeId : null,
RecruiterName = job.JobRecruiter != null ? job.JobRecruiter.name : string.Empty,
LocationId = job.fkLocationId,
Location = job.refJobLocation != null ? job.refJobLocation.jobLocation : "",
ContractTypeId = job.fkContractTypeId,
ContractType = job.refJobContractType != null ? job.refJobContractType.contractType : "",
CategoryId = job.fkCategoryId,
Category = job.refJobCategory != null ? job.refJobCategory.category : "",
ClosingDate = job.closingDate,
Featured = job.featured,
JobOfTheWeek = job.jobOfTheWeek,
PublishedDate = job.publishedDate,
Url = "/jobs/" + job.name.Replace(" ", "-").Replace("&", "and").Replace("'", "") + (job.fkLocationId.HasValue ? "-in-" + job.refJobLocation.jobLocation.Replace(" ", "-").Replace("&", "and").Replace("'", "") : "") + "-jn" + job.jobId,
CreatedOn = job.createdOnDate,
PrintWidth = job.printWidth,
PrintHeight = job.printHeight,
UntilFilled = (job.untilFilled != null && job.untilFilled.Value),
AdvertCost = job.advertCost,
DatesToShow = job.relJobDates.Where(x => x.fkJobId == job.jobId).Select(x => x.date).ToList(),
IsParentJob = job.relLinkedJobs != null && job.relLinkedJobs.Any(x => x.fkParentJobId == job.jobId),
IsAlternateWeekJob = job.alternateWeek != null && job.alternateWeek.Value,
Archived = job.archived,
LastModifiedDate = job.lastModifiedDate,
RecruiterContactDetails = job.recruiterContactDetails
};
}
The reason for this is because I want to be able to call "GetJobDetails" for returning a single job for example:
public JobExtended GetJobDetails(int jobId)
{
using (DataContext dc = new DataContext())
{
return dc.Jobs.Where(x => x.jobId == jobId).Select(j => GetJobDetails(j)).FirstOrDefault();
}
}
Doing it like this would allow me to only ever have to update the "GetJobDetails" method if for example I decided to add a new field of change how the "Url" value was generated but doing it this way is a lot slower. Is there a way around this, I have already tried the following which do not seem to help:
var test3 = (from job in dc.Jobs
where !job.archived
select job).AsEnumerable()
.Select(GetJobDetails).ToList();
var test4 = (from job in dc.Jobs
where !job.archived
select GetJobDetails(job));
var test4a = test4.ToList();
The reason TEST 1 is faster because the query is executed once on the server and only returns the selected fields.
var test = (from job in dc.Jobs
where !job.archived
select new JobExtended()
{
JobId = job.jobId,
NodeId = job.nodeId,
...
}).ToList();
When you call GetJobDetails in TEST 2 the parameter j needs to be materialized first before it can be send as parameter to GetJobDetails. And so there are multiple calls of the full objects.
return dc.Jobs.Where(x => x.jobId == jobId).Select(j => GetJobDetails(j)).FirstOrDefault();
In order to achieve something like you want you should use extension methods. This one extends IQueryable.
public static IEnumerable<JobExtended> SelectJobExtended(this IQueryable<Data.Job> query)
{
return query
.Select(o => new JobExtended()
{
JobId = job.jobId,
NodeId = job.nodeId,
...
}
}
Then you can call:
dc.Jobs.Where(x => x.jobId == jobId).SelectJobExtended().FirstOrDefault();
I've seen this kind of issue before. If I recall, what we did was "stacked" the queries.
public IEnumerable<JobExtended> ConvertToJobExtended(IEnumerable<Job> jobs)
{
return
from job in jobs
select new JobExtended()
{
MyString = job.MyInt.ToString(),
...
};
}
Then what you can do is call it the following way:
var query = (from job in dc.Jobs
where !job.archived
select job;
var test2 = ConvertToJobExtended(query).ToList();
There are plenty of alternatives that can go from here... I hope this goes in the right direction of what you're looking to do.

Entity Framework IQueryable Deferred for Big Object with many conditions LinqtoEntity

I'm attempting to refactor some painfully slow code in the repository layer of a large property management system.
There was a pattern followed by the original dev team where they did not understand the nature of deferred execution in regards to the IQueryable.
Here is a code sample:
public PropertyDTO GetPropertyByPropertyAuctionID(Guid propertyAuctionId)
{
PropertyDTO property = null;
var result =
(
from pa in databaseContext.PropertyAuction
join a in databaseContext.Auction on pa.AuctionID equals a.AuctionID into suba
from sa in suba.DefaultIfEmpty()
join an in databaseContext.AuctionNotifications
on sa.AuctionNotificationsID equals an.AuctionNotificationsID into suban
from san in suban.DefaultIfEmpty()
where pa.PropertyAuctionID == propertyAuctionId
where pa.IsDeleted == null || !(bool)pa.IsDeleted
select new
{
PropertyAuction = pa,
AuctionNotifications = san
}
).FirstOrDefault();
if (result != null)
{
var start = DateTime.Now;
property = ConvertPropertyFromDatabase(result.PropertyAuction, result.AuctionNotifications);
//end can be upwards of 10-12 seconds per record
var end = DateTime.Now - start;
}
else
{
throw CustomException.NotFound;
}
return property;
}
internal PropertyDTO ConvertPropertyFromDatabase(PropertyAuction propertyAuction, AuctionNotifications auctionNotifications = null)
{
Property property = null;
PropertyDTO dtoProperty = new PropertyDTO()
{
PropertyAuctionID = propertyAuction.PropertyAuctionID
};
if (propertyAuction.PropertyID.HasValue)
{
dtoProperty.PropertyID = propertyAuction.PropertyID.Value;
property = propertyAuction.Property;
dtoProperty.IsSimulcastAuction = propertyAuction.IsSimulcastAuction;
dtoProperty.IsSold = propertyAuction.IsSold;
dtoProperty.PropertyExecutionInitialValue = propertyAuction.ExecutionInitialValue;
}
if (propertyAuction.User4 != null && !string.IsNullOrEmpty(propertyAuction.User4.Profile1.FirstName) && !string.IsNullOrEmpty(propertyAuction.User4.Profile1.LastName))
{
dtoProperty.OfferAdministratorFirstName = propertyAuction.User4.Profile1.FirstName;
dtoProperty.OfferAdministratorLastName = propertyAuction.User4.Profile1.LastName;
dtoProperty.OfferAdministratorUserID = propertyAuction.OfferAdministratorUserID;
}
if (propertyAuction.AuctionID.HasValue)
{
dtoProperty.AuctionID = propertyAuction.AuctionID;
string auctionStartDateString = String.Empty;
if (propertyAuction.Auction != null)
{
if (propertyAuction.Auction.AuctionStartDate.HasValue)
{
auctionStartDateString = propertyAuction.Auction.AuctionStartDate.Value.Year + "-" + propertyAuction.Auction.AuctionStartDate.Value.Month.ToString().PadLeft(2, '0') + "-" + propertyAuction.Auction.AuctionStartDate.Value.Day.ToString().PadLeft(2, '0') + ": ";
}
dtoProperty.HMOnlineAuctionClosingStartDate = propertyAuction.Auction.AuctionClosingDate;
dtoProperty.AuctionName = auctionStartDateString + propertyAuction.Auction.Title;
dtoProperty.AuctionPublicSiteName = propertyAuction.Auction.PublicSiteName;
dtoProperty.AuctionNumber = propertyAuction.Auction.AuctionNumber;
dtoProperty.AuctionType = propertyAuction.Auction.AuctionType.Value;
dtoProperty.OriginalAuctionID = propertyAuction.Auction.OriginalAuctionID;
dtoProperty.AuctionTermsAndConditions = propertyAuction.Auction.TermsAndConditions;
dtoProperty.BrochureFileName = propertyAuction.Auction.BrochureFileName;
dtoProperty.BrochureName = propertyAuction.Auction.BrochureName;
if (propertyAuction.Auction.LuJohnsAuctionDetails != null)
{
dtoProperty.LuJohnsAuctionLiveWebcastLink = propertyAuction.Auction.LuJohnsAuctionDetails.LiveWebcastLink;
}
}
}
if (propertyAuction.PropertyStatus != null)
{
dtoProperty.PropertyStatusID = propertyAuction.PropertyStatusID.Value;
dtoProperty.PropertyStatusValue = propertyAuction.PropertyStatus.Value;
}
if (propertyAuction.PropertyAuctionAuctionDetails != null)
{
PropertyAuctionAuctionDetails propertyAuctionAuctionDetails = propertyAuction.PropertyAuctionAuctionDetails;
dtoProperty.PropertyAuctionAuctionDetailsId = propertyAuction.PropertyAuctionAuctionDetailsID;
SetShowOnWebsiteProperty(dtoProperty, propertyAuction);
SetWebsiteButtonProperty(dtoProperty, propertyAuctionAuctionDetails, propertyAuctionAuctionDetails.PreSaleMethod,
propertyAuctionAuctionDetails.AuctionMethod, propertyAuctionAuctionDetails.PostSaleMethod);
}
//This goes on for an astounding 900 more lines of code
}
As you can probably guess, this is making significant repeat trips to the database.
What is the fastest way to refactor this code to make the fewest number of trips to the database?
The problem here is that this ConvertPropertyFromDatabase() method triggers lots of queries for lazily loaded properties. I suggest you turn of lazy loading in you DbContext class like this:
Configuration.LazyLoadingEnabled = false;
Then you have to check which properties are accessed in this convert method, and rewrite your query so these are explicitly loaded.

create an array of anonymous type

I am trying to get data from database for Google charts in my program. I would like to create an array of anonymous type (var) instead of repeating my code over and over again:
public JsonResult GetChartData(int sID, int regionID)
{
var testPathOne = from p in _rep.GetMetricsData().GetLHDb().page_loads
where p.t_3id == sID && p.test_path_id == 1
select new { time = p.time, created_at = p.created_at };
var testPathTwo = from p in _rep.GetMetricsData().GetLHDb().page_loads
where p.t_3id == sID && p.test_path_id == 2
select new { time = p.time, created_at = p.created_at };
var tOne = testPathOne.ToArray();
var tTwo = testPathTwo.ToArray();
var name = new { test1 = tOne, test2 = tTwo };
return Json(name);
}
i know that i will need a for loop so i can go through all the test path id's instead of hard coding them like this p.test_path_id == 1, but my question is how would i make this part dynamic var name = new { test1 = tOne, test2 = tTwo };
Edit:
I apologize, I would like to do something like this:
name is an array
for loop:
testPath = query
name.Add(testPath)
I hope that makes sense
The easiest solution in this particular case would be to just give a name to the class that is currently anonymous. While there are workarounds that you can use, when you need to start working really hard to use an anonymous type you probably shouldn't be using it. It's there to make certain tasks quicker and easier; if that isn't happening then you are likely better off with a real class.
That solution would look something like this:
//Please give me a real name
public class ClassToBeRenamed
{
public DateTime Time { get; set; }
public DateTime CreatedAt { get; set; }
}
List<ClassToBeRenamed[]> myList = new List<ClassToBeRenamed[]>();
for (int i = 0; i < 10; i++)
{
myList.Add((from p in _rep.GetMetricsData().GetLHDb().page_loads
where p.t_3id == sID && p.test_path_id == i
select new ClassToBeRenamed { Time = p.time, CreatedAt = p.created_at })
.ToArray());
}
Having said all of that, it's still possible.
var myList = new[]{
from p in _rep.GetMetricsData().GetLHDb().page_loads
where p.t_3id == sID && p.test_path_id == 1
select new { time = p.time, created_at = p.created_at }.ToArray()
}.ToList();
for (int i = 2; i < 10; i++)
{
myList.Add(from p in _rep.GetMetricsData().GetLHDb().page_loads
where p.t_3id == sID && p.test_path_id == i
select new { time = p.time, created_at = p.created_at }.ToArray()
);
}
var myArray = myList.ToArray();
If it's really, really important that you have an array, and not a list, then you could call ToArray on myList at the very end. It's important that you start out with a list, and only convert it to an array at the end because Arrays have a fixed size once they are created. You can mutate their contents, but you can't make them bigger or smaller. A List on the other hand, is designed to mutate it's size over time, so it can start out with 0 or 1 items and then add items over time, which is important for us in this particular context. (It's actually useful quite often, which is why it is frequently useful to use List over arrays.)
Instead of using LINQ use foreach loops. You are more limited with LINQ.
Also define your ArrayLists at the beginning and add to them as you go.
var test1 = new ArrayList();
var test2 = new ArrayList();
foreach(PageLoad p in _rep.GetMetricsData().GetLHDb().page_loads)
{
if(p.t_3id == sID)
{
var tr = new { time = p.time, created_at = p.created_at };
switch(p.test_path_id)
{
case 1: test1.Add(tr); break;
case 2: test2.Add(tr); break;
}
}
}
return Json(new { test1, test2, });
You do not need to define the names of properties anonymous types because they default to the variable names.

finding a member property of an item in an array

I've passed in the whole sale object into this function. In that sale object, there are many childs e.g. saleOrderItem, Payment, User...
sale.payment is an array
Question:
1) How do I get the CodeNo from the `sale.payment' object? (as payment is an array)
2) How to get the sale.payment.CourseByTutor.TutorId (as payment is an array)
public static object GetSalesDataBySaleOrderID(SaleOrder sale)
{
return sale.saleOrderItem
.Where(s => s != null)
.Select(s => new {
Id = s.Id,
Username = sale.User.GetSingleUserById(s.UserId).Name,
Amount = s.Amount,
CodeNo = s.SaleOrder.payment.First().CodeNo,
TutorName = sale.User.GetSingleUserById(s.SaleOrder.payment.FirstOrDefault().CourseByTutor.TutorId).Name,
})
.ToList();
}
Here is how i bind the value to the object
private void SaveValueToObject()
{
saleOrder.UserId = UserInfo.Id;
saleOrder.Date = DateTime.Now;
for (int i = 0; i < dgSale.Rows.Count; i++)
{
SaleOrderItem SaleItem = new SaleOrderItem();
SaleItem.InventoryTypeId = Convert.ToInt32(dgSale.Rows[i].Cells["inventoryTypeId"].Value);
SaleItem.InventoryOrCourseId = Convert.ToInt32(dgSale.Rows[i].Cells["inventoryId"].Value);
SaleItem.Qty = Convert.ToInt32(dgSale.Rows[i].Cells["qty"].Value);
SaleItem.Amount = Convert.ToDecimal(dgSale.Rows[i].Cells["total"].Value);
SaleItem.UserId = Convert.ToInt32(dgSale.Rows[i].Cells["userId"].Value);
SaleItem.Discount = Convert.ToDecimal(dgSale.Rows[i].Cells["discount"].Value);
SaleItem.Remarks = (dgSale.Rows[i].Cells["remark"].Value == null) ? "" : dgSale.Rows[i].Cells["remark"].Value.ToString();
SaleItem.Status = (int)SaleOrderStatus.Active;
saleOrder.saleOrderItem[i] = SaleItem;
Payment p = new Payment();
p.PayType = Convert.ToInt32(dgSale.Rows[i].Cells["payType"].Value);
p.Code = (int)PaymentCode.RCT; // For Receipt prefix
p.CodeNo = p.GetNewReceiptNo(p.Code); //Check if it is receipt, if yes, Get last Receipt No + 1
p.UserId = (txtUserId.Text == string.Empty) ? 0 : Convert.ToInt32(txtUserId.Text);
p.Amount = Convert.ToDecimal(dgSale.Rows[i].Cells["total"].Value);
p.Remark = (dgSale.Rows[i].Cells["remark"].Value == null) ? "" : dgSale.Rows[i].Cells["remark"].Value.ToString();
p.PaymentMethodId = saleOrder.PaymentMethodId;
p.DateIssue = saleOrder.Date;
p.CourseByTutor.TutorId = Convert.ToInt32(dgSale.Rows[i].Cells["tutorId"].Value);
saleOrder.payment[i] = p;
}
}
I have a workaround and solved this question by adding the desired properties e.g. TutorId in the sale.saleOrderItem class. Thus making the direct access to the sale.SaleOrderItem.TutorId.
This sound stupid but it works.

Categories