Combine two records into one and update column - linq

I have the following records in my CartItems table:
When I migrate the cart, I'd like to combine the two records into one with the cart id of Test1 and then update the quantity to 2.
So it would be CartItemId 84, CartId Test1, Quantity 2, DateCreated 5/21/2013, ProductId 16
How would I do this in linq/EF?
EDIT
public void MigrateCart(string userName)
{
ShoppingCartId = GetCartId();
var shoppingCart = _context.ShoppingCartItems.Where(c => c.CartId == ShoppingCartId);
foreach (var item in shoppingCart)
{
item.CartId = userName;
}
_context.SaveChanges();
}
EDIT
I think I have it.
public void MigrateCart(string userName)
{
ShoppingCartId = GetCartId();
if (ShoppingCartId != userName)
{
var shoppingCart = _context.ShoppingCartItems.Where(c => c.CartId == ShoppingCartId).ToList();
var userShoppingCartItems = _context.ShoppingCartItems.Where(c => c.CartId == userName).ToList();
foreach (var item in shoppingCart)
{
foreach (var userShoppingCartItem in userShoppingCartItems)
{
if (item.ProductId == userShoppingCartItem.ProductId)
{
item.Quantity += userShoppingCartItem.Quantity;
item.CartId = userName;
_context.ShoppingCartItems.Remove(userShoppingCartItem);
}
}
item.CartId = userName;
}
_context.SaveChanges();
}
else
{
var shoppingCart = _context.ShoppingCartItems.Where(c => c.CartId == ShoppingCartId);
foreach (var item in shoppingCart)
{
item.CartId = userName;
}
_context.SaveChanges();
}
}

as you don't ask how to get the two items, I just give you a really rustic way.
var item1 = context.CartItems.FirstOrDefault(m => m.Id == 84);
var item2 = context.CartItems.FirstOrDefault(m => m.Id == 85);
item1.Quantity += item2.Quantity;//add quantity of item2 to item1
context.CartItems.Remove(item2);//remove item2
context.SaveChanges();

Related

Linq: group by with a non-unique key (preserving order)

Suppose the list is like a-a-a-b-b-a-c-c-c-a-a, how do I get the groups
{a-a-a}-{b-b}-{a}-{c-c-c}-{a-a}?
So not what I want is: {a-a-a-a-a-a}-{b-b}-{c-c-c}.
Try following code;
var list = new List<string>
{
"a","a","a","b","b","a","c","c","c","a","a"
};
int index = 0;
string lastItem = "";
var groupedList =
list
.Select(x =>
{
if (lastItem != x)
{
index++;
lastItem = x;
}
return new { Item = x,Index = index };
})
.GroupBy(grp => grp)
.Select(grp => grp.Select(x => x.Item).ToList())
.ToList();
Output
a,a,a
b,b
a
c,c,c
a,a
public static List<(string key, List<T> items)> GroupByConsecutive<T>(
IEnumerable<T> items,
Func<T, string> key)
{
var list = new List<(string key, List<T> items)>();
foreach (var item in items)
{
if (list.Count == 0 || list.Last().key != key(item))
{
list.Add((key(item), new List<T> { item }));
}
else
{
list.Last().items.Add(item);
}
}
return list;
}

How can I merge or combine two records into one using Linq?

I have the following table structure
ID firstName LastName zip Address
1 test1 test2 NULL NULL
2 test1 test2 12345 MI
I need to merge 2 accounts (primary & secondary) depending on IDs provided. For example, if I am given the values 1 (as primary) and 2 (as secondary) to merge.
The primary account (1) has NULL zip and Address so i need to copy those from secondary account (2) and update. The final result should be
ID firstName LastName zip Address
1 test1 test2 12345 MI
Is there any way to do using Linq or can another approach be recommended?
Though there is no native merge operator in LINQ you have a few options.
First, create your own merge!
public Account Merge(Account one, Account two) {
ret = new Account(){
Field = one.Field??two.Field
//Repeat for all fields
};
}
Then use (handwritten code, don't mind syntax errors)
var mergedResults = (from primary in primaryAccounts
join secondary in secondaryAccounts
on primary.Id equals secondary.Id
select new {Primary=primary, Secondary secondary})
.Select(x=>Merge(x.Primary,x.Secondary);
Second, do merge in the LINQ
Not differs much
var mergedResults = (from primary in primaryAccounts
join secondary in secondaryAccounts
on primary.Id equals secondary.Id
select new Account { Field = primary.Field??secondary.Field}; //Repeat for all fields
Mabe with my extension
public interface IMerge<out T>
{
IEnumerable<IMergeMatched<T>> Matched();
IEnumerable<IMergeMatched<T>> Matched(Func<T, T, bool> predicate);
IEnumerable<T> NotMatchedBySource();
IEnumerable<T> NotMatchedBySource(Func<T, bool> predicate);
IEnumerable<T> NotMatchedByTarget();
IEnumerable<T> NotMatchedByTarget(Func<T, bool> predicate);
}
public interface IMergeMatched<out T>
{
T Source { get; }
T Target { get; }
}
public static class Enumerable
{
public static IMerge<TSource> Merge<TSource>(this IEnumerable<TSource> source, IEnumerable<TSource> target,
Func<TSource, TSource, bool> predicate)
{
return new Merge<TSource>(source, target, predicate);
}
}
public class Merge<T> : IMerge<T>
{
private readonly Func<T, T, bool> _predicate;
private readonly IEnumerable<T> _source;
private readonly IEnumerable<T> _target;
private IEnumerable<IMergeMatched<T>> _matcheds;
private IEnumerable<T> _notMatchedBySource;
private IEnumerable<T> _notMatchedByTarget;
public Merge(IEnumerable<T> source, IEnumerable<T> taget, Func<T, T, bool> predicate)
{
_source = source;
_target = taget;
_predicate = predicate;
}
public IEnumerable<IMergeMatched<T>> Matched()
{
if (_matcheds == null)
{
Analize();
}
return _matcheds;
}
public IEnumerable<IMergeMatched<T>> Matched(Func<T, T, bool> predicate)
{
return Matched()
.Where(t => predicate.Invoke(t.Source, t.Target))
.ToArray();
}
public IEnumerable<T> NotMatchedBySource()
{
if (_notMatchedBySource == null)
{
Analize();
}
return _notMatchedBySource;
}
public IEnumerable<T> NotMatchedBySource(Func<T, bool> predicate)
{
return NotMatchedBySource()
.Where(predicate)
.ToArray();
}
public IEnumerable<T> NotMatchedByTarget()
{
if (_notMatchedByTarget == null)
{
Analize();
}
return _notMatchedByTarget;
}
public IEnumerable<T> NotMatchedByTarget(Func<T, bool> predicate)
{
return NotMatchedByTarget()
.Where(predicate)
.ToArray();
}
private void Analize()
{
var macheds = new List<MergeMached<T>>();
var notMachedBySource = new List<T>(_source);
var notMachedByTarget = new List<T>(_target);
foreach (var source in _source)
{
foreach (var target in _target)
{
var macth = _predicate.Invoke(source, target);
if (!macth) continue;
macheds.Add(new MergeMached<T>(source, target));
notMachedBySource.Remove(source);
notMachedByTarget.Remove(target);
}
}
_matcheds = macheds.ToArray();
_notMatchedBySource = notMachedBySource.ToArray();
_notMatchedByTarget = notMachedByTarget.ToArray();
}
}
public class MergeMached<T> : IMergeMatched<T>
{
public MergeMached(T source, T target)
{
Source = source;
Target = target;
}
public T Source { get; private set; }
public T Target { get; private set; }
}
How to use?
[TestMethod]
public void TestMerge()
{
var source = new List<MediaFolder>
{
new MediaFolder
{
Id = "Id1",
Name = "Name1",
Path = "Path1"
},
new MediaFolder
{
Id = "Id2",
Name = "Name2",
Path = "Path2"
},
new MediaFolder
{
Id = "Id3",
Name = "Name3",
Path = "Path3"
},
new MediaFolder
{
Id = "Id4",
Name = "Name4",
Path = "Path4"
},
new MediaFolder
{
Id = "Id5",
Name = "Name5",
Path = "Path5"
},
new MediaFolder
{
Id = "Id6",
Name = "Name6",
Path = "Path6"
}
};
var target = new List<MediaFolder>
{
new MediaFolder
{
Id = "Id1",
Name = "Actualizado en el objeto",
Path = "Path1"
},
//Id2 eliminado
new MediaFolder
{
Id = "Id3",
Name = "Name3",
Path = "Actualizado tambien"
},
new MediaFolder
{
Id = "Id4",
Name = "Name4",
Path = "Path4"
},
new MediaFolder
{
Id = "Id5",
Name = "Name5",
Path = "Path5"
},
new MediaFolder
{
Id = "Id6",
Name = "Name6",
Path = "Path6"
},
new MediaFolder
{
Id = "Id7",
Name = "Nuevo Item 7",
Path = "Nuevo Item 7"
}
};
var merge = source.Merge(target, (x, y) => x.Id == y.Id);
var toUpdate = merge.Matched((x, y) => x.Name != y.Name | x.Path != y.Path)
.ToArray();
var toDelete = merge.NotMatchedBySource();
var toInsert = merge.NotMatchedByTarget();
Assert.AreEqual(2, toUpdate.Count());
Assert.IsTrue(toUpdate.Count(x => x.Source.Id == "Id1" & x.Target.Id == "Id1") > 0);
Assert.IsTrue(toUpdate.Count(x => x.Source.Id == "Id3" & x.Target.Id == "Id3") > 0);
Assert.AreEqual("Id7", toInsert.First().Id);
Assert.AreEqual("Id2", toDelete.First().Id);
}
[TestMethod]
public void TestMerge2()
{
var source = new List<CustomObject>
{
new CustomObject
{
Year = 2010,
Month = 6,
Value = 2
},
new CustomObject
{
Year = 2010,
Month = 7,
Value = 5
},
new CustomObject
{
Year = 2010,
Month = 10,
Value = 3
}
};
var target = new List<CustomObject>
{
new CustomObject
{
Year = 2010,
Month = 7,
Value = 2
},
new CustomObject
{
Year = 2010,
Month = 8,
Value = 1
},
new CustomObject
{
Year = 2010,
Month = 10,
Value = 2
}
};
var merge = source.Merge(target, (x, y) => x.Year == y.Year && x.Month == y.Month);
var toUpdate = merge.Matched((x, y) => x.Value != y.Value)
.ToArray();
var inSourceButNotInTarget = merge.NotMatchedBySource();
var inTargetButNotInSource = merge.NotMatchedByTarget();
Console.WriteLine("Objects to Update");
foreach (var mergeMatched in toUpdate)
{
Console.WriteLine("{0} -{1} - {2} - {3}",
mergeMatched.Source.Year,
mergeMatched.Source.Month,
mergeMatched.Source.Value,
mergeMatched.Target.Value);
}
Console.WriteLine("In source but not in target");
foreach (var customObject in inSourceButNotInTarget)
{
Console.WriteLine("{0} -{1} - {2} - 0",
customObject.Year,
customObject.Month,
customObject.Value);
}
Console.WriteLine("In target but not in source");
foreach (var customObject in inTargetButNotInSource)
{
Console.WriteLine("{0} -{1} - 0 - {2}",
customObject.Year,
customObject.Month,
customObject.Value);
}
}

Re-using code in controller class

The following code is taken from the tutorial: http://www.asp.net/mvc/tutorials/getting-started-with-aspnet-mvc3/cs/examining-the-edit-methods-and-edit-view which shows how ASP.net MVC 3 can be used to manage a movie database.
In the tutoral, a list object is added to the controller class that contains every movie genre that exists in the database. This list is then passed to a drop-down in the view enabling the database to be searched by genre.
Controller: (code related to movie genre in bold)
public ActionResult SearchIndex(string movieGenre, string searchString)
{
var GenreLst = new List<string>();
var GenreQry = from d in db.Movies
orderby d.Genre
select d.Genre;
GenreLst.AddRange(GenreQry.Distinct());
ViewBag.movieGenre = new SelectList(GenreLst);
var movies = from m in db.Movies
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title.Contains(searchString));
}
if (string.IsNullOrEmpty(movieGenre))
return View(movies);
else
{
return View(movies.Where(x => x.Genre == movieGenre));
}
}
What I want to do is enhance this further so that the movies can be searched by price as well as genre. I know I can re-use the much of the same code to do this. I think I need to create a new class that the controller class can pass either the genre or price. Is this correct? IF so, I'd appreciate an example. Thanks.
Update/Clarification:
I want to avoid repeating the code for both genre and price as below:
public ActionResult SearchIndex(string movieGenre, string searchString,float moviePrice)
{
var GenreLst = new List<string>();
var GenreQry = from d in db.Movies
orderby d.Genre
select d.Genre;
GenreLst.AddRange(GenreQry.Distinct());
ViewBag.movieGenre = new SelectList(GenreLst);
var PriceLst = new List<string>();
var PriceQry = from d in db.Movies
orderby d.Genre
select d.Genre;
PriceLst.AddRange(GenreQry.Distinct());
ViewBag.moviePrice = new SelectList(PriceLst);
var movies = from m in db.Movies
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title.Contains(searchString));
}
if (string.IsNullOrEmpty(movieGenre))
return View(movies);
else
{
return View(movies.Where(x => x.Genre == movieGenre));
}
if (string.IsNullOrEmpty(moviePrice))
return View(movies);
else
{
return View(movies.Where(x => x.Genre == moviePrice));
}
}
You just have to insert a text box in the view to get price value. Then receive this value at action and modify the query to get desired results.
like this:
#Html.ActionLink("Create New", "Create")
#using (Html.BeginForm()){
<p>Genre: #Html.DropDownList("movieGenre", "All")
Title: #Html.TextBox("SearchString")
Price: #Html.TextBox("Price")
<input type="submit" value="Filter" /></p>
}
And in the action method you are using the code below to populate the dropdownlist with genre values. You need not do the same for price value.
var GenreLst = new List<string>();
var GenreQry = from d in db.Movies
orderby d.Genre
select d.Genre;
GenreLst.AddRange(GenreQry.Distinct());
ViewBag.movieGenre = new SelectList(GenreLst);
And in your action method you just have to use the value of price to filter data
public ActionResult SearchIndex(string movieGenre, string searchString,float price)
{
var GenreLst = new List<string>();
var GenreQry = from d in db.Movies
orderby d.Genre
select d.Genre;
GenreLst.AddRange(GenreQry.Distinct());
ViewBag.movieGenre = new SelectList(GenreLst);
var movies = from m in db.Movies
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title.Contains(searchString));
}
if (string.IsNullOrEmpty(movieGenre))
return View(movies);
else
{
return View(movies.Where((x => x.Genre == movieGenre) &&(x => x.Price== price)));
}
}
You can do it in so many different ways while all are correct but it depends on the complexity of your project. Basically you don't want to over-engineer a simple program. But in general you should move all of your logic to a separate class and use your actions for creating and calling the right logic class:
public class GetMoviesRequest
{
public string Name { get; set; }
public float? Price { get; set; }
}
public class MoviesLogic
{
private List<Movie> Movies;
public IEnumerable<Movie> Get(GetMoviesRequest request)
{
IEnumerable<Movie> filtered = Movies.AsQueryable();
if (!string.IsNullOrEmpty(request.Name))
{
//Filter by name
filtered = filtered.Where(m => m.Name == request.Name);
}
if (request.Price.HasValue)
{
//Filter by value
filtered = filtered.Where(m => m.Price == request.Price);
}
return filtered;
}
}
public class MyController
{
public ActionResult SearchIndex(string movieGenre, string searchString)
{
var logic = new MoviesLogic();
var movies = logic.Get(new GetMoviesRequest() { Name = searchString } )
///do stuff with movies
}
}

Rendering a hierarchy using LINQ?

Let say we have a class
Category
{
ID,
Name,
ParentID
}
and a List
1, 'Item 1', 0
2, 'Item 2', 0
3, 'Item 3', 0
4, 'Item 1.1', 1
5, 'Item 3.1', 3
6, 'Item 1.1.1', 4
7, 'Item 2.1', 2
Can we using LINQ to render a tree like:
Item 1
Item 1.1
Item 1.1.1
Item 2
Item 2.1
Item 3
Item 3.1
Any help is appreciated!
Here's the "LINQ-only" version:
Func<int, int, string[]> build = null;
build = (p, n) =>
{
return (from x in categories
where x.ParentID == p
from y in new[]
{
"".PadLeft(n)+ x.Name
}.Union(build(x.ID, n + 1))
select y).ToArray();
};
var lines = build(0, 0);
Yes, it's recursive LINQ.
Per NVA's request, here's the way to make all "orphan" records become root records:
Func<IEnumerable<int>, int, string[]> build = null;
build = (ps, n) =>
{
return (from x in categories
where ps.Contains(x.ParentID)
from y in new[]
{
"".PadLeft(n)+ x.Name
}.Union(build(new [] { x.ID }, n + 1))
select y).ToArray();
};
var roots = (from c in categories
join p in categories on c.ParentID equals p.ID into gps
where !gps.Any()
orderby c.ParentID
select c.ParentID).Distinct();
var lines = build(roots, 0);
These extension methods do exactly what you want:
public static partial class LinqExtensions
{
public class Node<T>
{
internal Node() { }
public int Level { get; internal set; }
public Node<T> Parent { get; internal set; }
public T Item { get; internal set; }
public IList<Node<T>> Children { get; internal set; }
}
public static IEnumerable<Node<T>> ByHierarchy<T>(
this IEnumerable<T> source,
Func<T, bool> startWith,
Func<T, T, bool> connectBy)
{
return source.ByHierarchy<T>(startWith, connectBy, null);
}
private static IEnumerable<Node<T>> ByHierarchy<T>(
this IEnumerable<T> source,
Func<T, bool> startWith,
Func<T, T, bool> connectBy,
Node<T> parent)
{
int level = (parent == null ? 0 : parent.Level + 1);
if (source == null)
throw new ArgumentNullException("source");
if (startWith == null)
throw new ArgumentNullException("startWith");
if (connectBy == null)
throw new ArgumentNullException("connectBy");
foreach (T value in from item in source
where startWith(item)
select item)
{
var children = new List<Node<T>>();
Node<T> newNode = new Node<T>
{
Level = level,
Parent = parent,
Item = value,
Children = children.AsReadOnly()
};
foreach (Node<T> subNode in source.ByHierarchy<T>(possibleSub => connectBy(value, possibleSub),
connectBy, newNode))
{
children.Add(subNode);
}
yield return newNode;
}
}
public static void DumpHierarchy<T>(this IEnumerable<Node<T>> nodes, Func<T, string> display)
{
DumpHierarchy<T>(nodes, display, 0);
}
private static void DumpHierarchy<T>(IEnumerable<LinqExtensions.Node<T>> nodes, Func<T, string> display, int level)
{
foreach (var node in nodes)
{
for (int i = 0; i < level; i++) Console.Write(" ");
Console.WriteLine (display(node.Item));
if (node.Children != null)
DumpHierarchy(node.Children, display, level + 1);
}
}
}
You can use them as follows:
categories.ByHierarchy(
cat => cat.ParentId == null, // assuming ParentId is Nullable<int>
(parent, child) => parent.Id == child.ParentId)
.DumpHierarchy(cat => cat.Name);
You can use recursion:
public class Category
{
public int ID { get; set; }
public string Name { get; set; }
public int ParentID { get; set; }
public List<Category> Children { get; set; }
}
class Program
{
static void Main()
{
List<Category> categories = new List<Category>()
{
new Category () { ID = 1, Name = "Item 1", ParentID = 0},
new Category() { ID = 2, Name = "Item 2", ParentID = 0 },
new Category() { ID = 3, Name = "Item 3", ParentID = 0 },
new Category() { ID = 4, Name = "Item 1.1", ParentID = 1 },
new Category() { ID = 5, Name = "Item 3.1", ParentID = 3 },
new Category() { ID = 6, Name = "Item 1.1.1", ParentID = 4 },
new Category() { ID = 7, Name = "Item 2.1", ParentID = 2 }
};
List<Category> hierarchy = new List<Category>();
hierarchy = categories
.Where(c => c.ParentID == 0)
.Select(c => new Category() { ID = c.ID, Name = c.Name, ParentID = c.ParentID, Children = GetChildren(categories, c.ID) })
.ToList();
HieararchyWalk(hierarchy);
Console.ReadLine();
}
public static List<Category> GetChildren(List<Category> categories, int parentId)
{
return categories
.Where(c => c.ParentID == parentId)
.Select(c => new Category { ID = c.ID, Name = c.Name, ParentID = c.ParentID, Children = GetChildren(categories, c.ID) })
.ToList();
}
public static void HieararchyWalk(List<Category> hierarchy)
{
if (hierarchy != null)
{
foreach (var item in hierarchy)
{
Console.WriteLine(string.Format("{0} {1}", item.ID, item.Name));
HieararchyWalk(item.Children);
}
}
}
}
public IEnumerable<HelpPageMenuItem> GetHelpPageMenuItems()
{
var helpPages = (from h in Context.HelpPages select new HelpPageMenuItem{HelpPageId = h.HelpPageId, ParentHelpPageId = h.ParentHelpPageId, PageContext = h.PageContext, MenuText = h.MenuText}).ToList();
var parents = from h in helpPages where !h.ParentHelpPageId.HasValue select PopulateChildren(h, helpPages);
return parents.ToList();
}
private static HelpPageMenuItem PopulateChildren(HelpPageMenuItem helpPageMenuItem, IEnumerable<HelpPageMenuItem> helpPages)
{
helpPageMenuItem.ChildHelpPages =
(from h in helpPages
where h.ParentHelpPageId == helpPageMenuItem.HelpPageId
select PopulateChildren(h, helpPages)).ToList();
return helpPageMenuItem;
}
#model List<OrgChart.Models.Node>
#{
Func<int?, List<OrgChart.Models.Node>, string> recuresive = null;
recuresive = (parentid, list) => string.Join("", list.Where(x => x.ParentId == parentid).Select(x => "<li>" + x.Name + "<ul>" + recuresive(x.Id, list.Where(y => y.ParentId != parentid).ToList()) + "</ul></li>"));
}
#Html.Raw("<ul id='org1' >" + recuresive(null, Model) + "</ul>")
<div id="chart" class="orgChart"></div>
public static List<TSource> BuildTreeView<TSource, TKey>(this List<TSource> allItems
, Func<TSource, TKey> parentSelector, Func<TSource, TKey> childSelector, Expression<Func<TSource, List<TSource>>> childrenPropertySelector
, Func<TSource, bool> GetRoot, List<TSource> rootList = null)
{
if (rootList == null)
rootList = allItems.Where(GetRoot).ToList();
if (rootList != null && rootList.Count > 0)
{
rootList.ForEach(rootItem =>
{
Func<TSource, bool> whereClause = x => childSelector(rootItem).Equals(parentSelector(x));
var childrenProperty = (childrenPropertySelector.Body as MemberExpression).Member as System.Reflection.PropertyInfo;
var childrenList = allItems.Where(whereClause).ToList();
childrenProperty.SetValue(rootItem, childrenList);
if (childrenList.Count > 0)
BuildTreeView(allItems, parentSelector, childSelector, childrenPropertySelector, GetRoot, childrenProperty.GetValue(rootItem) as List<TSource>);
});
}
return rootList;
}
//Call method
List<Channel> rootChannel = listChannel.BuildTreeView(f => f.PARENT_CODE, x => x.CODE, z => z.SubChannels, c => c.CODE == "AC");

linq null parameter

how can i do the code
static string BuildMenu(List<Menu> menu, int? parentId)
{
foreach (var item in menu.Where(i => i.ParentMenu == parentId || i.ParentMenu.MenuId == parentId).ToList())
{
}
}
return BuildMenu(menuList,null);
so if parentId==null then return only records i => i.ParentMenu == null but when parentId is >0 then return records with i.ParentMenu.MenuId == parentId
You could do that in a single statement, probably something like this
var query = from menu in menus
where (parentId == null ? menu.ParentMenu == null : menu.ParentMenu != null && menu.ParentMenu.MenuId == parentId)
select menu;
But I think it would be more readable by breaking it up like the following
var query = menus.AsEnumerable();
if (parentId.HasValue)
query = query.Where(m => m.ParentMenu != null && m.ParentMenu.MenuId == parentId);
else
query = query.Where(m => m.ParentMenu == null);
Full example:
public class Menu
{
public Menu ParentMenu { get; set; }
public int MenuId { get; set; }
}
...
static void Main(string[] args)
{
List<Menu> menus = new List<Menu>();
for (int i = 0; i < 4; i++)
{
menus.Add(new Menu() { MenuId = i });
}
menus[2].ParentMenu = menus[0];
menus[3].ParentMenu = menus[1];
Console.WriteLine(BuildMenu(menus, 1));
Console.Read();
}
static string BuildMenu(List<Menu> menus, int? parentId)
{
var query = menus.AsEnumerable();
if (parentId.HasValue)
query = query.Where(m => m.ParentMenu != null && m.ParentMenu.MenuId == parentId);
else
query = query.Where(m => m.ParentMenu == null);
StringBuilder builder = new StringBuilder();
foreach (Menu menu in query)
{
// build your string
builder.Append(menu.MenuId + ";");
}
return builder.ToString();
}

Resources