Bulk updates using linq entities - linq

I have a list of object like
List
category has properties, CategoryId, CategoryName, Categorymessage,
I have to use this list to update records in the database table
Categories, which has the same columns CategoryId, CategoryName, CategoryMessage
for the items in list which have a matching CategoryId as in the database table
How can I do that as a bulk update, using Entity framework extensions,
the examples I saw have the update value hard coded like below, (statusId =2),
whereas for me that value has to be retrieved from the item in the list which matches the categoryId in the database table.
context.Tasks.Update(
t => t.StatusId == 1,
t => new Task {StatusId = 2});
Thanks in advance.

I am not sure whether this what you are looking for? I haven't run this code.
List<Category> categoryList = new List<Category> {
new Category { Id = 1, Message = "A", Name = "A"},
new Category { Id = 2, Message = "B", Name = "B"},
new Category { Id = 3, Message = "C", Name = "C"},
new Category { Id = 4, Message = "D", Name = "D"},
};
using (var container = new Model1Container())
{
IQueryable<Category> categoryQueryable = container.Categories.Where(x => categoryList.Any(t => t.Id == x.Id));
foreach (Category item in categoryQueryable)
{
var categorySource = categoryList.Where(x => x.Id == item.Id).Select(m => m).FirstOrDefault();
item.Message = categorySource.Message;
item.Name = categorySource.Message;
}
container.SaveChanges();
}

Related

Group by with maximum

I want to group by category, show it's name, then show the highest id that is related to it. Here's some data and the result that I want further down. Any ideas? I've been playing around with GroupJoin but can't seem to get it to work.
My Data
var stuff = new[] {
new {id = 5, catId = 2},
new {id = 56, catId = 2},
new {id = 56, catId = 2},
new {id = 8, catId = 1},
new {id = 9, catId = 3}};
var categories = new[] {
new {catId = 1, Name = "Water"},
new {catId = 4, Name = "Wind"},
new {catId = 2, Name = "Fire"}};
What I want my results to look like
Water - 8
Wind - null
Fire - 56
categories
.GroupJoin
(
stuff,
c=>c.catId,
s=>s.catId,
(c,s)=>new
{
c.Name,
Max = s.Any() ? (int?)s.Max (m => m.id) : null
}
);
It seems that you want a "LEFT OUTER JOIN" with LINQ:
var query = from cat in categories
join s in stuff
on cat.catId equals s.catId into gj
from stuffJoin in gj.DefaultIfEmpty()
group stuffJoin by new { cat.catId, cat.Name } into catGroup
select new {
Category = catGroup.Key.Name,
MaxID = catGroup.Max(s => s == null ? 0 : s.id) // stuff is null for Wind
};
foreach (var x in query)
Console.WriteLine("Category: {0} Max-ID: {1}", x.Category, x.MaxID);
Outputs:
Category: Water Max-ID: 8
Category: Wind Max-ID: 0
Category: Fire Max-ID: 56

How to iterate through GroupBy groups using Dynamic LINQ? [duplicate]

I am using Dynamic Linq helper for grouping data. My code is as follows :
Employee[] empList = new Employee[6];
empList[0] = new Employee() { Name = "CA", State = "A", Department = "xyz" };
empList[1] = new Employee() { Name = "ZP", State = "B", Department = "xyz" };
empList[2] = new Employee() { Name = "AC", State = "B", Department = "xyz" };
empList[3] = new Employee() { Name = "AA", State = "A", Department = "xyz" };
empList[4] = new Employee() { Name = "A2", State = "A", Department = "pqr" };
empList[5] = new Employee() { Name = "BA", State = "B", Department = "pqr" };
var empqueryable = empList.AsQueryable();
var dynamiclinqquery = DynamicQueryable.GroupBy(empqueryable, "new (State, Department)", "it");
How can I get back the Key and corresponding list of grouped items i.e IEnumerable of {Key, List} from dynamiclinqquery ?
I solved the problem by defining a selector that projects the Key as well as Employees List.
var eq = empqueryable.GroupBy("new (State, Department)", "it").Select("new(it.Key as Key, it as Employees)");
var keyEmplist = (from dynamic dat in eq select dat).ToList();
foreach (var group in keyEmplist)
{
var key = group.Key;
var elist = group.Employees;
foreach (var emp in elist)
{
}
}
The GroupBy method should still return something that implements IEnumerable<IGrouping<TKey, TElement>>.
While you might not be able to actually cast it (I'm assuming it's dynamic), you can certainly still make calls on it, like so:
foreach (var group in dynamiclinqquery)
{
// Print out the key.
Console.WriteLine("Key: {0}", group.Key);
// Write the items.
foreach (var item in group)
{
Console.WriteLine("Item: {0}", item);
}
}

Sort a field of each object in a list with LINQ

Is is possible to sort an item in a IEnumerable list using LINQ?
For example:
IEnumerable<sample> sam = new List<sample>()
{
new sample{ id = 1, name = "sample 1", list = new List<int>{5,6,1}},
new sample{ id = 2, name = "sample 1", list = new List<int>{2,9}},
new sample{ id = 3, name = "sample 1", list = new List<int>{8,3,7}},
new sample{ id = 4, name = "sample 1", list = new List<int>{8,4,3}},
new sample{ id = 5, name = "sample 1", list = new List<int>{5,1,7}},
new sample{ id = 6, name = "sample 1", list = new List<int>{6,9,7}}
};
The expected output from the sample given above would be the sorted values in List.
Expected output is:
sample{ id = 1, name = "sample 1", list = new List<int>{1,5,6}},
sample{ id = 2, name = "sample 1", list = new List<int>{2,9}},
sample{ id = 3, name = "sample 1", list = new List<int>{3,7,8},
sample{ id = 4, name = "sample 1", list = new List<int>{3,4,8}},
sample{ id = 5, name = "sample 1", list = new List<int>{1,5,7}},
sample{ id = 6, name = "sample 1", list = new List<int>{6,7,9}}
thanks
Try,
sam.All(p => { p.list.Sort(); return true; });
((List<sample>)sam).ForEach(s => s.list.Sort());
The general shape for LINQ is that it does not change the original data. For example, if we have a list
var ints = new List<int>{5,6,1};
and use linq to 'sort it'
var sorted = ints.OrderBy();
we end up with two lists
ints => { 5,6,1}
sorted => {1,5,6}
In your above example, it depends on what you want the output to be
If you want a new list of samples where the list is sorted then you can use
var newSampleList = samples.Select( sam => new Sample {
id = sam.id,
name = sam.name,
list = new List<int>(sam.list.OrderBy())
});
If you do not want to create a new list but want to sort the values in place it is not really what LINQ is intended for but it can be done using something like AVD's answer to execute functionality on each member (in this case call Sort on the list).
NOTE: This will only work if sample.list is defined as a List() as Sort() only exists on List<>. If defined as IList or IEnumerable it will not work.

asp.net mvc3, why my dropdownlist is not selected?

I create my selectlist from enum.
[Flags]
public enum Age
{
New_Born = 1,
Toddler = 2,
Preschool = 4,
Kindergarten = 8,
Elementary_School = 16,
Middle_School = 32,
High_School = 64
}
var age = from Age e in Enum.GetValues(typeof(Age))
select new { Id = (int)e, Name = e.ToString().Replace("_", " ") };
I tried both:
var ageList = new SelectList(age, "Id", "Name", (int)Model.Child.Age);
or
var ageList = new SelectList(age, "Id", "Name", Model.Child.Age);
#Html.DropDownListFor(m => m.Child.Age, ageList, "Your Child's Age")
Everything works except the selected value didn't get selected.
EDIT: after hours testing, finally fix it.
chagne Id = (int)e to Id = e.
var age = from Age e in Enum.GetValues(typeof(Age))
select new { Id = e, Name = e.ToString().Replace("_", " ") };
var ageList = new SelectList(age, "Id", "Name", Model.Child.Age);
I just created a similar example and worked out your problem and I believe you have two problems with your code:
In your controller code, you should have your first option, like this:
SelectList selectList = new SelectList(items, "Id", "Name", (int)Qualities.Whatever);
And in your view:
<%= this.Html.DropDownListFor(m => m.List.SelectedValue, this.Model.List, "Qualities") %>
Think about it, why would you pass the SelectList twice? You should pass the selected value and then the list of values.
The fact that I didn't use Razor view engine is irrelevant.
after hours testing, finally fix it. chagne Id = (int)e to Id = e.
var age = from Age e in Enum.GetValues(typeof(Age))
select new { Id = e, Name = e.ToString().Replace("_", " ") };
var ageList = new SelectList(age, "Id", "Name", Model.Child.Age);

How do I transfer this logic into a LINQ statement?

I can't get this bit of logic converted into a Linq statement and it is driving me nuts. I have a list of items that have a category and a createdondate field. I want to group by the category and only return items that have the max date for their category.
So for example, the list contains items with categories 1 and 2. The first day (1/1) I post two items to both categories 1 and 2. The second day (1/2) I post three items to category 1. The list should return the second day postings to category 1 and the first day postings to category 2.
Right now I have it grouping by the category then running through a foreach loop to compare each item in the group with the max date of the group, if the date is less than the max date it removes the item.
There's got to be a way to take the loop out, but I haven't figured it out!
You can do something like that :
from item in list
group item by item.Category into g
select g.OrderByDescending(it => it.CreationDate).First();
However, it's not very efficient, because it needs to sort the items of each group, which is more complex than necessary (you don't actually need to sort, you just need to scan the list once). So I created this extension method to find the item with the max value of a property (or function) :
public static T WithMax<T, TValue>(this IEnumerable<T> source, Func<T, TValue> selector)
{
var max = default(TValue);
var withMax = default(T);
var comparer = Comparer<TValue>.Default;
bool first = true;
foreach (var item in source)
{
var value = selector(item);
int compare = comparer.Compare(value, max);
if (compare > 0 || first)
{
max = value;
withMax = item;
}
first = false;
}
return withMax;
}
You can use it as follows :
from item in list
group item by item.Category into g
select g.WithMax(it => it.CreationDate);
UPDATE : As Anthony noted in his comment, this code doesn't exactly answer the question... if you want all items which date is the maximum of their category, you can do something like that :
from item in list
group item by item.Category into g
let maxDate = g.Max(it => it.CreationDate)
select new
{
Category = g.Key,
Items = g.Where(it => it.CreationDate == maxDate)
};
How about this:
private class Test
{
public string Category { get; set; }
public DateTime PostDate { get; set; }
public string Post { get; set; }
}
private void Form1_Load(object sender, EventArgs e)
{
List<Test> test = new List<Test>();
test.Add(new Test() { Category = "A", PostDate = new DateTime(2010, 5, 5, 12, 0, 0), Post = "A1" });
test.Add(new Test() { Category = "B", PostDate = new DateTime(2010, 5, 5, 13, 0, 0), Post = "B1" });
test.Add(new Test() { Category = "A", PostDate = new DateTime(2010, 5, 6, 12, 0, 0), Post = "A2" });
test.Add(new Test() { Category = "A", PostDate = new DateTime(2010, 5, 6, 13, 0, 0), Post = "A3" });
test.Add(new Test() { Category = "A", PostDate = new DateTime(2010, 5, 6, 14, 0, 0), Post = "A4" });
var q = test.GroupBy(t => t.Category).Select(g => new { grp = g, max = g.Max(t2 => t2.PostDate).Date }).SelectMany(x => x.grp.Where(t => t.PostDate >= x.max));
}
Reformatting luc's excellent answer to query comprehension form. I like this better for this kind of query because the scoping rules let me write more concisely.
from item in source
group item by item.Category into g
let max = g.Max(item2 => item2.PostDate).Date
from item3 in g
where item3.PostDate.Date == max
select item3;

Resources