Best way to remove items which are not anymore in collection - c#

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();
}

Related

Is manual foreach loop faster or linq query on collections in the following scenario?

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.

Entity Framework get linked entities (faster result)

I have a SQL database with several tables which are linked together.
"Project" table: Contains informations about projects
"Release" table: Contains informations about releases which are related to projects (one project -> multiple releases; one release -> one project)
"IssuesSW" table: Contains informations about issues which are related to releases (one issueSW -> linked in multiple releases; one release -> contains multiple issuesSW)
In my first solution I just returned the full list of about 10.000 issues but for additional filtering options (based on the projects/releases the issues depends on) I need additional data from the projects and the releases.
The first solution I had took about 2 seconds until the request (and the drawing of some charts on the front end) finished but with the additional data I had to start on the project level and go down till I reach the issues and that takes much too long now.
In my current solution I just used foreach loops to go threw the projects and find their releases and then go threw the releases and find all the issues:
[HttpPost]
public JsonResult GetReleasesWithIsws()
{
using (var db = new SwMetricsContext())
{
var result = new List<GetCustomerReleasesWithIswsResult>();
var projects = db.Projects.ToList();
foreach (var project in projects)
{
var releases = db.PVERs.Where(x => x.Project_ID == project.ID).ToList();
foreach(var release in releases)
{
var pver_result = new GetCustomerReleasesWithIswsResult()
{
Project_Id = project.ID,
Project_Title = project.Title,
Project_Generation = project.Generation,
Project_DefaultDevelopmentMethod = project.DefaultDevelopmentMethod,
Release_Id = release.ID,
Release_Category = release.Category,
Release_Classification = release.Classification,
Release_Department = project.ResponsibleAtBosch,
Release_ImplementationFreeze = release.ImplementationFreeze,
Release_LifeCycleState = release.LifeCycleState,
Release_PlannedDate = release.PlannedDate,
Release_SpecificationFreeze = release.SpecificationFreeze,
Release_Title = release.Title,
Release_Type = release.Type
};
var isw_connections = db.PVERIssuesSW.Where(x => x.Release_ID == release.ID).ToList().Select(x => x.IssueSW_ID).ToHashSet();
var isws = db.IssuesSW.Where(x => isw_connections.Contains(x.ID)).ToList();
pver_result.Release_Isws.AddRange(isws);
result.Add(pver_result);
}
}
var json = Json(result);
json.MaxJsonLength = int.MaxValue;
return json;
}
}
But the problem with this solution is it takes much too long (about 30 seconds).
So if someone has a better solution for me I would be very thankful :)
Here are the 3 database table models:
[Table("DGSIT_SWMetrics_Projects")]
public class Project
{
public string ID { get; set; }
public string Title { get; set; }
public int Customer_ID { get; set; }
public string Responsible { get; set; }
public string DefaultDevelopmentMethod { get; set; }
public string Generation { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
public string SpjmName { get; set; }
}
[Table("DGSIT_SWMetrics_PVERs")]
public class Pver // Release
{
public string ID { get; set; }
public string Project_ID { get; set; }
public string Type { get; set; }
public string Title { get; set; }
public string PlannedDate { get; set; }
public string ImplementationFreeze { get; set; }
public string SpecificationFreeze { get; set; }
public string LifeCycleState { get; set; }
public string Category { get; set; }
public string Classification { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
}
[Table("DGSIT_SWMetrics_IssuesSW")]
public class IssueSW
{
public string Project_ID { get; set; }
public string ID { get; set; }
public string Title { get; set; }
public string LCS { get; set; }
public string Category { get; set; }
public string DevelopmentMethod { get; set; }
public string Allocation { get; set; }
public string Tags { get; set; }
public string SubmitDate { get; set; }
public string ExternalReview { get; set; }
public int Assignee_ID { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
}
IssueSW has it´s own "Project_ID" because it depends on one "Cluster-Project". But it´s also linked to the Releases with an extra table:
[Table("DGSIT_SWMetrics_PVERIssuesSW")]
public class PVERIssueSw
{
public int ID { get; set; }
public string Release_ID { get; set; }
public string IssueSW_ID { get; set; }
}

Improve nested foreach performance C#

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.

Can I add a List<> of unknown type to a class?

I have a class defined as:
public class ReportObjectInformation
{
public string tableName { get; set; }
public int progressBarValue { get; set; }
public int rowCount { get; set; }
public bool canConnect { get; set; }
public int index { get; set; }
public string summaryFile { get; set; }
public string reportFile { get; set; }
public string errorFile { get; set; }
}
I currently have seven different lists of objects in my code. Is there a way I can do something like:
public class ReportObjectInformation
{
public string tableName { get; set; }
public int progressBarValue { get; set; }
public int rowCount { get; set; }
public bool canConnect { get; set; }
public int index { get; set; }
public string summaryFile { get; set; }
public string reportFile { get; set; }
public string errorFile { get; set; }
public List<> listOne { get; set; } // add this
public List<> listTwo { get; set; } // add this
}
And then in my code set the list to be one of my seven predefined types of lists?
One of my other lists is made up of this class:
class parameters
{
public string firstName{ get; set; }
public string lastName{ get; set; }
public string address{ get; set; }
public string city{ get; set; }
public string state { get; set; }
public string country{ get; set; }
public string active_flag { get; set; }
}
which I create in my code as:
List<parameters> parm_list = new List<parameters>();
The parm_list is populated with data. Now I want to add that list to this other object I'm creating. At other times in my code I'll want to set the list to one of the my other types but for now how would I do this? Is this even possible?
ReportObjectInformation reportObject = new ReportObjectInformation();
reportObject.tableName = "UserInformation";
reportObject.listOne = parm_list;
reportObject.listTwo = someother_list;
If you can guarantee that a particular instance of ReportObjectInformation will work with a given type of List you can do this:
public class ReportObjectInformation<TOne, TTwo>
{
public string tableName { get; set; }
public int progressBarValue { get; set; }
public int rowCount { get; set; }
public bool canConnect { get; set; }
public int index { get; set; }
public string summaryFile { get; set; }
public string reportFile { get; set; }
public string errorFile { get; set; }
public List<TOne> listOne { get; set; }
public List<TTwo> listTwo { get; set; }
}
Which lets you specify which types you want the ReportObjectInformation object lists to use.
You could make ReportObjectInformation generic
public class ReportObjectInformation<TOne, TTwo>
{
public List<TOne> listOne { get; set; } // add this
public List<TTwo> listTwo { get; set; } // add this
}
Then create an instance like this
var reportInfo = new ReportObjectInformation<parameters, otherClass>();
reportInfo.listOne = new List<parameters>();
reportInfo.listTwo = new List<otherClass>();
Of course this means that each instance can not switch to hold a list of one of the other types.
Well, since you want to assign of lists of different types to the object during runtime, you'll be left with no type checking. Can be implemented like:
public class ContainingClass
{
public IList SomeList { get; set; }
}
then you can do
var c = new ContainingClass();
c.SomeList = new List<int> { 1, 2, 3 };
c.SomeList = new List<string> { "abc", "def" };
foreach (var member in c.SomeList)
Console.WriteLine(member);
But you should only do this as a last resort, generally prefer using generics or clean design, because this is:
Slow - you'll have to cast a lot since IList works with object
Unsafe - who knows what list is there at a given time? Not to mention you'll be left without compile-time type checks (those are very powerful to have, try not to lose them).
Generally consider this a no-go unless you really really really have no choice (e.g. legacy code compatibility).

How to get values from class list inside a class using linq

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
}
}

Categories