i have this following classes, in a windows store app project.
public class Meeting
{
public string Id { get; set; }
public string Organizer { get; set; }
public string Organization { get; set; }
public string Name { get; set; }
public string MeetingType { get; set; }
public string Description { get; set; }
public Address Address { get; set; } //X = LAT; Y=LNG
public DateTime StartDate { get; set; }
public DateTime EndTime { get; set; }
public string Status { get; set; }
public List<MeetingPoint> MeetingPoints { get; set; }
public List<MeetingInvitee> Invitees { get; set; }
}
and this one
public class MeetingPoint
{
public string id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int Position { get; set; }
public List<Attchments> Attachments { get; set; }
public List<MeetingPoint> SubPoints { get; set; }
public int AttachmentNumber { get; set; }
public string details { get; set; }
public string executiveSummary { get; set; }
public string presenter { get; set; }
public string coPresenter { get; set; }
public Double duration { get; set; }
public string purpose { get; set; }
public string supportedBy { get; set; }
public int num { get; set; }
}
In one of the pages, i do a search that looks like this, where i try to get the Attachments in each SubPoint of each MeetingPoint
foreach (var item in meeting.MeetingPoints)
{
foreach (var sub in item.SubPoints)
{
foreach (var at in sub.Attachments)
{
...
}
}
My question is if there is a more effective way of doing this, since having 3 nested foreach takes about 4 or 5 seconds.
I'm not certain about performance increase, I think you may see some, but if you want to get away from nested loops consider using lambda/SelectMany to get to the lowest collection you need to iterate over to do work against. In other words, if you're only going to be operating against attachments then consider something like this:
var greatGandChildrenFlattened = parent.Children.SelectMany(c => c.GrandChildren.SelectMany(gc => gc.GreatGrandChildren));
foreach (var item in greatGandChildrenFlattened)
{
//do work on item
}
You can try to replace some of the foreach blocks with Parallel.ForEach. Just look for this in the output window "EventSourceException: No Free Buffers available from the operating system (e.g. event rate too fast)" and if it happens, replace one of the Parallel.ForEach invocations with a normal foreach block. This happens if events are fired too quickly and it may have a negative impact on the performance instead of helping you.
Related
I want to know which approach is faster. I have the following class:
public class AccountBalance
{
public long AccountID { get; set; }
public string AccountNumber { get; set; }
[NotRequiredForDataTable]
public IEnumerable<AccountMediaBalance> AccountMediaBalances { get; set; }
}
public class AccountMediaBalance
{
public long AccountID { get; set; }
public long MediaID { get; set; }
public string MediaSerialNumber { get; set; }
public decimal? CashAmount { get; set; }
public int FareID { get; set; }
public bool ShowID { get; set; }
public bool ShareCash { get; set; }
public bool ShareToken { get; set; }
public bool SharePass { get; set; }
public IEnumerable<Token> Tokens { get; set; }
public IEnumerable<Pass> Passes { get; set; }
}
public class Token
{
public long TokenID { get; set; }
public long AccountID { get; set; }
public long MediaProductID { get; set; }
public long MediaID { get; set; }
public long? ActivateByMediaID { get; set; }
public string SerialNumber { get; set; }
public decimal? TransferValue { get; set; }
public DateTimeOffset CreateTime { get; set; }
public DateTimeOffset? ActivateTime { get; set; }
public DateTimeOffset? ExpiryTime { get; set; }
}
public class Pass
{
public long MediaProductID { get; set; }
public long AccountID { get; set; }
public long MediaID { get; set; }
public int ProductID { get; set; }
public long? ActivateByMediaID { get; set; }
public string SerialNumber { get; set; }
public DateTimeOffset CreateTime { get; set; }
public DateTimeOffset? ActivateTime { get; set; }
public DateTimeOffset? ExpiryTime { get; set; }
}
I have a list of AccountBalance data as List<AccountBAlance> and I want to transform data in a way that I want to separate AccountMediaBalance collection in one list, All tokens in one list and all passes in a separate list.
There are two approaches for doing this:
public void SaveAccountBalances(List<AccountBalance> accountBalances)
{
if (accountBalances != null)
{
var mediaBalances = accountBalances.SelectMany(x => x.AccountMediaBalances ??
Enumerable.Empty<AccountMediaBalance>()).ToList();
var tokens = mediaBalances.SelectMany(x => x.Tokens ?? Enumerable.Empty<Token>()).ToList();
var passes = mediaBalances.SelectMany(x => x.Passes ?? Enumerable.Empty<Pass>()).ToList();
}
}
The other approach would be like following:
public void SaveAccountBalances(List<AccountBalance> accountBalances)
{
var mediaBalances = new List<AccountMediaBalance>();
var tokens = new List<Token>();
var passes = new List<Pass>();
if (accountBalances != null)
{
foreach (var item in accountBalances)
{
mediaBalances.AddRange(item.AccountMediaBalances ?? Enumerable.Empty<AccountMediaBalance>());
}
foreach (var item in mediaBalances)
{
tokens.AddRange(item.Tokens ?? Enumerable.Empty<Token>());
passes.AddRange(item.Passes ?? Enumerable.Empty<Pass>());
}
}
}
Performance is a big concern. Can anyone put me in the right direction and let me know which approach is faster and why?
foreach loop uses GetEnumerator directly, while linq creates the query object first and then GetEnumerator. So it is naturally a little bit faster to use foreach loop for a single iteration but it still makes the code look better to use linq.
I have an object that has header level details about an order, as well as a list of order details.
The header information populates just fine, but I can't figure out how to bind the list of order details to the tablix that I have on the report.
Is this the wrong approach?
The data connection is being determined at run time, so I don't think I can easily just hook a subreport to a database and pass filters.
Edit: I should add that I have a parent form with a ReportViewer, if it makes a difference. That's where I set the datasource.
public class FormulaHeaderModel
{
public string flavor { get; set; }
public string name { get; set; }
public string author { get; set; }
public string formulaId { get; set; }
public string formulaNumber { get; set; }
public string formulaType { get; set; }
public string accessLevel { get; set; }
public string createdOnDate { get; set; }
public string formulaWeight { get; set; }
public string note { get; set; }
public List<FormulaDetailModel> dataCharacterizing { get; set; }
public List<FormulaDetailModel> dataContributory { get; set; }
public List<FormulaDetailModel> dataGlobal { get; set; }
public List<FormulaDetailModel> dataCarrier { get; set; }
}
public class FormulaDetailModel
{
public int formulaID { get; set; }
public int ingredientTypeId { get; set; }
public string codeFema { get; set; }
public decimal ingredientCost { get; set; }
public string name { get; set; }
public string natural { get; set; }
public decimal ppm { get; set; }
public decimal percentSolution { get; set; }
public decimal grams {get; set;}
}
I need to have a tablix for each of the lists.
So the top is the string level info, then a label and tablix(or whatever really) for each of the 4 FormulaDetailModel lists.
Got it. I can add a second datasource as long as the name matches the dataset name that the table is set for.
this.reportViewer1.LocalReport.DataSources.Add(new ReportDataSource("FormulaDetailModel", fhModel.dataCharacterizing ));
I have a classic Order item in my database:
public partial class ORDERS
{
public ORDERS()
{
this.ORDER_DETAIL = new HashSet<ORDER_DETAIL>();
}
public int ORDER_IDE { get; set; }
public string ORDER_STATE { get; set; }
public decimal ORDER_TOTAL { get; set; }
public decimal ORDER_TAXES { get; set; }
public decimal ORDER_SHIPPING_COST { get; set; }
public decimal ORDER_HANDLING_COST { get; set; }
public Nullable<System.DateTime> ORDER_SHIPPING_DATE { get; set; }
public string ORDER_BILLING_NAME { get; set; }
public string ORDER_BILLING_ADDRESS { get; set; }
public string ORDER_BILLING_CITY { get; set; }
public string ORDER_BILLING_REGION { get; set; }
public string ORDER_BILLING_COUNTRY { get; set; }
public string ORDER_BILLING_POSTAL_CODE { get; set; }
public string ORDER_SHIPPING_NAME { get; set; }
public string ORDER_SHIPPING_ADDRESS { get; set; }
public string ORDER_SHIPPING_CITY { get; set; }
public string ORDER_SHIPPING_REGION { get; set; }
public string ORDER_SHIPPING_COUNTRY { get; set; }
public string ORDER_SHIPPING_POSTAL_CODE { get; set; }
public string ORDER_COMMENT { get; set; }
public decimal ORDER_DETAIL_AMOUNT { get; set; }
public string ORDER_DESCRIPTION { get; set; }
public decimal ORDER_DISCOUNT { get; set; }
public virtual ICollection<ORDER_DETAIL> ORDER_DETAIL { get; set; }
}
As you can see, this items has a collection of ORDER_DETAIL. In my project I want to save the modifications made to the order and keep only the current order details. So I am doing this:
public void SaveOrderModifications(ORDERS _orderToReceive)
{
using (mDb = new DatabaseEntity())
{
mDb.Database.Connection.Open();
var orderQry = from o in mDb.ORDERS
where o.ORDER_IDE == _orderToReceive.mOrderID
select o;
ORDERS originalOrder = orderQry.FirstOrDefault();
if (originalOrder == null)
{
throw new Exception("Invalid operation");
}
mDb.Entry(originalOrder).CurrentValues.SetValues(_orderToReceive);
mDb.SaveChanges();
}
}
So if my original order had 3 items, and my new order has 8, and from this order 2 of the original order were dumped, what do I need to do to effectively only keep the 8 new items? Do I need to iterate through all of them to see which ones are there, and which one aren't there anymore?
EDIT
I have found a solution, which is not elegant and consumes a bit of process:
foreach (var orderDetail in originalOrder.ORDER_DETAIL.ToList())
{
mDb.ORDER_DETAIL.Remove(orderDetail);
mDb.SaveChanges();
}
foreach (var orderDetail in orderToSave.ORDER_DETAIL)
{
mDb.ORDER_DETAIL.Add(orderDetail);
mDb.SaveChanges();
}
it implies that I flush all the older ORDER_DETAIL object before adding the new one, but I'm still looking for a more elegant / better way of doing things.
Typically I do it the same way you are doing it, but I check to see if the item is on the new one and only add and remove the changed items. It adds some elegance because you can use a Linq expression.
Something to the effect of:
foreach (var orderDetail in originalOrder.ORDER_DETAIL.Where(d => !newOrder.ORDER_DETAIL.Contains(d)).ToList())
{
mDb.ORDER_DETAIL.Remove(orderDetail);
mDb.SaveChanges();
}
I'm writing simple imageviewer for one imageboard. I'm using these 2 classes for navigation(navigation parameter for Frame.Navigate() method) in my app:
public class KonaParameter
{
public int page { get; set; }
public string tags { get; set; }
public KonaParameter()
{
page = 1;
}
}
public class Post
{
public int id { get; set; }
public string tags { get; set; }
public int created_at { get; set; }
public int creator_id { get; set; }
public string author { get; set; }
public int change { get; set; }
public string source { get; set; }
public int score { get; set; }
public string md5 { get; set; }
public int file_size { get; set; }
public string file_url { get; set; }
public bool is_shown_in_index { get; set; }
public string preview_url { get; set; }
public int preview_width { get; set; }
public int preview_height { get; set; }
public int actual_preview_width { get; set; }
public int actual_preview_height { get; set; }
public string sample_url { get; set; }
public int sample_width { get; set; }
public int sample_height { get; set; }
public int sample_file_size { get; set; }
public string jpeg_url { get; set; }
public int jpeg_width { get; set; }
public int jpeg_height { get; set; }
public int jpeg_file_size { get; set; }
public string rating { get; set; }
public bool has_children { get; set; }
public object parent_id { get; set; }
public string status { get; set; }
public int width { get; set; }
public int height { get; set; }
public bool is_held { get; set; }
public string frames_pending_string { get; set; }
public List<object> frames_pending { get; set; }
public string frames_string { get; set; }
public List<object> frames { get; set; }
public object flag_detail { get; set; }
}
The problem I faced is that suspending doesn't work. SuspensionManager throws "SuspensionManager failed" exception after await SuspensionManager.SaveAsync(); call(I googled that it's because of using complex types).
I tried to use string as a navigation parameter. It works, but I need more than 1 string for my parameter(List<string> doesn't work, I tried to use it).
How to suspend my app correctly?
The problem is that SuspensionManager uses Frame.GetNavigationState() to get the history of the Frame. It then tries to serialise the navigation history to a string, unfortunately it has no way to know how to serialise custom complex types as parameters like Post or KonaParameter and fails with an exception.
If you want to use SuspensionManager then you'll need to restrict yourself to simple types like int or string as parameters.
If you do need complex types then it's best to store them in some background service / repository with an identifier. You can then pass the identifier as the parameter.
The recommended approach is to serialize your "state" object, so it can be saved/restored as a string. You can use Json.NET to do this:
//save state
Post post = //...;
string state = JsonConvert.Serialize(post)
//restore state
Post post = JsonConvert.Deserialize<Post>(state);
If you want to use two objects (a Post and a KonaParameter), I'd consider creating an "aggregate" class that encapsulates both, and serializing/deserializing that instead:
public class State
{
public Post post {get; set;}
public KonaParameter param {get; set;}
}
I would like to access class members values inside of list inside of a class. My classes look like this. The SureViewEvents class contains the parent level details for an incoming alarm and the SureViewEventDetails are the detail values for the alarm. I want to loop through class SureViewEvents using LINQ and loop through the details rows if any are populated.
How can I go about doing this?
public class SureViewEvents
{
public string EventId { get; set; }
public string GroupId { get; set; }
public string DateTimeCreated { get; set; }
public string GroupTitle { get; set; }
public string EventTitle { get; set; }
public string SubscriberId { get; set; }
public bool Closed { get; set; }
public List<SureViewEventDetails> Details { get; set; }
}
//EventID|EventRecordID|CreatedDate|EventRecordTypeID|Details|Input1|Input2|EventCode|SubscriberID|EventTitle|SerialNo
public class SureViewEventDetails
{
public string EventId { get; set; }
public string EventRecordID { get; set; }
public string CreateDate { get; set; }
public string EventRecordTypeID { get; set; }
public string Details { get; set; }
public string Area { get; set; }
public string Zone { get; set; }
public string EventCode { get; set; }
public string SubscriberID { get; set; }
public string EventTitle { get; set; }
public int SerialNo { get; set; }
public bool Handled { get; set; }
}
I can retrieve the parent level values using the following, but I am not exactly sure how to access the Details that have been populated using this structure. Any advice is appreciated!
var activeEvents = (from sve in m_sureViewEvents
select sve).ToList();
lock (m_driverLock)
{
foreach (var activeEvent in activeEvents)
{
if (activeEvent.Closed == false)
{
m_fepConnector.HandleAlarms();
DownloadZipArchive(activeEvent.EventId);
CloseSureViewEvent(activeEvent.EventId);
}
}
}
You can select all the details with SelectMany:
foreach (var details in activeEvents.SelectMany(e => e.Details))
{
// ... Stuff
}
This will get all the SureViewEventDetails that are in all the activeEvents.
Inside your loop for each activeEvent you can simply loop through the details:
foreach (var activeEvent in activeEvents)
{
foreach (var eventDetail in activeEvent.Details)
{
// do something with the detail
}
}