how to update observable collection group - linq

I have implemented group observable collection like below.
Grouped Property
private ObservableCollection<Grouping<String, Request>> _groupedList = null;
public ObservableCollection<Grouping<String, Request>> GroupedList {
get {
return _groupedList;
}
set {
_groupedList = value;
RaisePropertyChanged(() => GroupedList);
}
}
Creating List
var list = new List<Request>();
var grouped = from Model in list
group Model by Model.Done into Group
select new Grouping<string, Request>(Group.Key, Group);
GroupedList = new ObservableCollection<Grouping<string, TModel>>(grouped);
Now i need to update one item in the list without reloading full list for performance.
i did tried like this , mylist.FirstOrDefault(i => i.Id== mymodel.Id); Not worked for me.
I need to pick that particular item and edit and update into the list again using linq or something but i stuck here for group observable collection no efficient details to do this., anybody having idea about this help please.
And finally i get updated single item, but i need to do that without
GroupedList = new ObservableCollection<Grouping<string, TModel>>(grouped);
Because everytime it create new list and bind into my view.Thats again big performance though.
Thanks in advance.

What I understand from your question is that you want to push an updated group without overwriting the entire ObservableCollection.
To do that:
var targetGroup = GroupedList.FirstOrDefault(i => i.Id == mymodel.Id);
var targetIndex = GroupedList.IndexOf(targetGroup);
var modifiedGroup = ... //Do whatever you want to do
GroupedList[targetIndex] = modifiedGroup;
This will trigger a 'replace' operation of the target grouping.

Related

How do I save multiple selections from List to EF Model?

I am trying to learn how to submit multiple selections from a list to the model created between two data models. I have tried the following:
var tag = context.TagInformation.Find(model.Tags[0]);
var newlyCreatedUser = context.Users.Find(user.Id);
newlyCreatedUser.TagInfo = new List<TagInformation>(0) { tag };
context.SaveChanges();
I have also tried the following:
var tags = new List<TagInformation>();
foreach (var tag in model.Tags)
{
var tag= context.TagInformation.Find(model.Tags[0]);
if (tag != null)
{
tags.Add(tag);
}
}
var newlyCreatedUser = context.Users.Find(user.Id);
newlyCreatedUser.TagInfo = tags;
context.SaveChanges();
I have searched on Google and tried to find what value I need to change here in order to save all selected values from model.Tags, but currently only the first selected value is saved. To my understanding, the [0] is causing it to only save the first selected tag. I need to automatically save any combination of selected tags from the List, regardless of how many tags are in the list.
I can see that all of the select tags are loaded during debugging, and the foreach statement gets passed through for each selected id, but still only saves the first tag selected in the list.
What must I change to obtain this result and where can I find documentation to help me understand? Thanks in advance.
var tag= context.TagInformation.Find(model.Tags[0]);
this line of code always select the first tag, you should do something like
var tag= context.TagInformation.Find(tag);

LINQ to SQL . how to select all record using .take()

var result=(from refridgerators in context.A
group refridgerators by new { refridgerators.Id, refridgerators.Name } into gr
select new DAO<String>
{
Key = gr.Key.Name,
Count = gr.Count()
}).OrderByDescending(k => k.Count).Take(numberOfRecords).ToList();
This is my linq to sql query this is working perfectly fine.
this shows top 5 records (sorted by their count) if i pass numberOfRecords =5.
now my problem is i don`t want to modify query. so what should i do in above query to show all records. This is in relation with my requirement i want to use same query to show all refridgerators and Top 5 , top 10 refridgerators.
I am not sure if it is possible using LINQ. but i guess there must be something related to this.
I would simply don't add the Take to the query but to the code where you consume this query.
So for example:
public static IEnumerable<DAO> GetRefrigerators()
{
var query = from refridgerators in context.A
group refridgerators by new { refridgerators.Id, refridgerators.Name } into gr
select new DAO<String>
{
Key = gr.Key.Name,
Count = gr.Count()
};
return query.OrderByDescending(k => k.Count);
}
Now you can either use:
var refrigerators = GetRefrigerators().Take(5).ToList();
or
var refrigerators = GetRefrigerators().Take(10).ToList();
or
var refrigerators = GetRefrigerators().ToList();
I'd make numberOfRecords a int? and if the value is null you should not call Take(numberOfRecords)
var result = (from refridgerators in context.A
group refridgerators by new { refridgerators.Id, refridgerators.Name } into gr
select new DAO<String>
{
Key = gr.Key.Name,
Count = gr.Count()
}).OrderByDescending(k => k.Count);
if(numberOfRecords.HasValue)
result = result.Take(numberOfRecords.Value);
return result.ToList();
I know it changes your query a little bit but I believe it is pretty acceptable, adding a numberOfRecords of a super high value adds an overheard to your query which isn't useful in your case.
So this post is very old, I know, but my solution is not provided (maybe someone wants to achieve the same after 2 years, like me):
You could create your own extension-method that also works with linq 2 sql. Example:
public static class LinqExtensions
{
public static IEnumerable<TResult> TakeIfNotNull<TResult>(this IEnumerable<TResult> source, int? count)
{
return !count.HasValue ? source : source.Take(count.Value);
}
}
this takes an int? instead of int and returns either the source-enumerable if count is null else it returns the result of default Take-method.
So you could write like:
.OrderByDescending(k => k.Count).TakeIfNotNull(numberOfRecords).ToList();
if numberOfCounts is null, it'll take all records.
As the right solution has already been posted by Tim, still I want your attention to the simpler solution, if suits to your requirement.
Add one more if condition at the top of this query.
if(allRecordRequired)
{
numberOfRecords = 2000000;
}
Leave your query as it is.
Pass a huge number to your method.A number that is equal (at least) or bigger than the items count.That should give you all records.

LINQ ForEach with Replace

I am trying to replace a string date value "01/01/1700" with an empty string in LINQ.
The date is of type string.
Something like this but I cant get it to work.
Query<Client>(sql).ToList().ForEach(x => x.DateOfBirth =
x.DateOfBirth.Replace("01/01/1700", ""));
This code works but its not LINQ.
var result = Query<Client>(sql).ToList();
foreach (var client in result)
{
if (client.DateOfBirth == "01/01/1700")
{
client.DateOfBirth = "n/a";
}
}
Thanks for your help.
The problem is the ToList(). The result is not visible in the variable you use afterwards.
Try out the following:
var list = Query<Client>(sql).ToList();
list.ForEach(l => l.DateOfBirth = l.DateOfBirth.Replace("01/01/1700", "n/a"));
Should work fine. Use the list variable afterwards.
var result = Query<Client>(sql).ToList();
result.ForEach(l => l.DateOfBirth = l.DateOfBirth.Replace("01/01/1700", "n/a"));
Your code assumes that changes made to an object in a List will be reflected in the Query<Client> that the object came from. Apparently this is not the case. One thing you could try is assigning the list before calling ForEach() and using the list from that point on:
var clients = Query<Client>(sql).ToList();
clients.ForEach(x => x.DateOfBirth = x.DateOfBirth.Replace("01/01/1700", ""));
Also, ForEach is not a LINQ operator. It is a method in the List class. Unlike LINQ operators, it will modify the list that called it and will not return anything. The way to "modify" data with LINQ is by using select:
var clients = (from client in Query<Client>(sql).ToList()
select new Client(client)
{
DateOfBirth = client.DateOfBirth.Replace("01/01/1700", "")
}).ToList();

LINQ (Dynamic): OrderBy within a GroupBy using dynamic linq?

I had the following query using normal linq and it was working great (using anonymous type),
var result = from s in Items
group s by s.StartTime into groupedItems
select new {groupedItems.Key, Items= groupedItems.OrderBy(x => x.Name) };
But using Dynamic Linq I cannot get it to order by within the groupby.
result = Items.GroupBy("StartTime", "it").OrderBy("Name");
It states the Name isn't available. It is worth noting that if I take my OrderBy off, everything works great but items inside each "Key" are not ordered.
This is a good question!
I simulated your situation by creating a class called Item.
public class Item
{
public DateTime StartTime { get; set; }
public string Name { get; set; }
}
and then created a basic list of items to do the groupby.
List<Item> Items = new List<Item>()
{
new Item() { StartTime = DateTime.Today, Name = "item2"},
new Item() { StartTime = DateTime.Today, Name = "item1"},
new Item() { StartTime = DateTime.Today.AddDays(-1), Name = "item3"},
};
Now the big difference in the 2 queries is where the order by is being performed. In the first query, when you perform groupedItems.OrderBy(x => x.Name) its being performed on a IGrouping<DateTime,Item> or a single entry as it iterates through all the groupings.
In the second query, the orderby is being performed after the fact. This means you're doing an orderby on a IEnumerable<IGrouping<DateTime,Item>> because the iterations have already happened.
Since Microsoft was nice they added something to help deal with this for expressions. This overload allows you to specify the item returned as it iterates through the collection. Here's an example of the code:
var expressionResult = Items.GroupBy(x => x.StartTime,
(key, grpItems) => new { key, Items = grpItems.OrderBy(y => y.Name) });
The second part of the GroupBy you can specify a lambda expression that takes a key and a grouping of items under that key and return an entry that you specify, which is the same as you're doing in the original query.
Hope this helps!

linqToSql related table not delay loading properly. Not populating at all

I have a couple of tables with similar relationship structure to the standard Order, OrderLine tables.
When creating a data context, it gives the Order class an OrderLines property that should be populated with OrderLine objects for that particular Order object.
Sure, by default it will delay load the stuff in the OrderLine property but that should be fairly transparent right?
Ok, here is the problem I have: I'm getting an empty list when I go MyOrder.OrderLines but when I go myDataContext.OrderLines.Where(line => line.OrderId == 1) I get the right list.
public void B()
{
var dbContext = new Adis.CA.Repository.Database.CaDataContext(
"<connectionString>");
dbContext.Connection.Open();
dbContext.Transaction = dbContext.Connection.BeginTransaction();
try
{
//!!!Edit: Imortant to note that the order with orderID=1 already exists
//!!!in the database
//just add some new order lines to make sure there are some
var NewOrderLines = new List<OrderLines>()
{
new OrderLine() { OrderID=1, LineID=300 },
new OrderLine() { OrderID=1, LineID=301 },
new OrderLine() { OrderID=1, LineID=302 },
new OrderLine() { OrderID=1, LineID=303 }
};
dbContext.OrderLines.InsertAllOnSubmit(NewOrderLines);
dbContext.SubmitChanges();
//this will give me the 4 rows I just inserted
var orderLinesDirect = dbContext.OrderLines
.Where(orderLine => orderLine.OrderID == 1);
var order = dbContext.Orders.Where(order => order.OrderID == 1);
//this will be an empty list
var orderLinesThroughOrder = order.OrderLines;
}
catch (System.Data.SqlClient.SqlException e)
{
dbContext.Transaction.Rollback();
throw;
}
finally
{
dbContext.Transaction.Rollback();
dbContext.Dispose();
dbContext = null;
}
}
So as far as I can see, I'm not doing anything particularly strange but I would think that orderLinesDirect and orderLinesThroughOrder would give me the same result set.
Can anyone tell me why it doesn't?
You're just adding OrderLines; not any actual Orders. So the Where on dbContext.Orders returns an empty list.
How you can still find the property OrderLines on order I don't understand, so I may be goofing up here.
[Edit]
Could you update the example to show actual types, especially of the order variable? Imo, it shoud be an IQueryable<Order>, but it's strange that you can .OrderLines into that. Try adding a First() or FirstOrDefault() after the Where.

Resources