Assume the following model. Note the self-referencing relationship "parent".
public class Category
{
public virtual long Id { get; set; }
public virtual string Name { get; set; }
public virtual Category Parent { get; set; }
public virtual long? ParentId { get; set; }
}
My data are as follows:
id | name | parentId
1--------tag 1 ----- null
2--------tag 2 ----- 1
3--------tag 3 ----- 1
4--------tag 4 ----- 2
5--------tag 5 ----- null
6--------tag 6 ----- null
I want to write a query that data will be sorted as follows
tag 1
----->tag 2
----->----->tag 4
----->tag 3
tag 5
tag 6
This is my code
var categorys = __categories
.AsNoTracking()
.ToList();
I do not know how to sort them
Well I would describe that more as hierarchical organisation as opposed to sorting, but here is an example of how you can achieve it quite simply. Note, this is not very optimised as the search for each Parent Category requires potentially a full scan of the entire Category list, but it's a good starting point:
using System;
using System.Collections.Generic;
using System.Linq;
namespace SimpleTree
{
public class Program
{
private static void Main(string[] args)
{
var categories = new List<Category>()
{
new Category {Id = 1, Name = "tag 1"},
new Category {Id = 2, Name = "tag 2", ParentId = 1},
new Category {Id = 3, Name = "tag 3", ParentId = 1},
new Category {Id = 4, Name = "tag 4", ParentId = 2},
new Category {Id = 5, Name = "tag 5"},
new Category {Id = 6, Name = "tag 6"},
};
foreach (var category in categories)
{
category.Parent = FindParent(categories, category.ParentId);
}
//pretty printing with indentation is left as an exercise for you :)
foreach (var category in categories)
{
Console.WriteLine("ID:{0} Name:{1} ParentID:{2}", category.Id, category.Name, category.ParentId);
}
Console.ReadLine();
}
private static Category FindParent(IEnumerable<Category> categories, long? parentId)
{
if (parentId == null) return null;
return categories.FirstOrDefault(c => c.Id == parentId);
}
}
public class Category
{
public virtual long Id { get; set; }
public virtual string Name { get; set; }
public virtual Category Parent { get; set; }
public virtual long? ParentId { get; set; }
}
}
Output
ID:1 Name:tag 1 ParentID:
ID:2 Name:tag 2 ParentID:1
ID:3 Name:tag 3 ParentID:1
ID:4 Name:tag 4 ParentID:2
ID:5 Name:tag 5 ParentID:
ID:6 Name:tag 6 ParentID:
Note that depending on your use case, you might find it useful to include a ChildCategories collection on the Category object, and fill this as well, so that it's easy to walk the tree in either direction.
Try this recursive function
class Program
{
static void Main(string[] args)
{
using (var db = new aaContext2())
{
Temp temp = new Temp();
var cc = db.Catagory.FirstOrDefault();
IList<Category> parentList =new List <Category>();
foreach (Category catagory in db.Catagory.Where(cat => cat.ParentId == null))
{
parentList.Add(temp.Recursive(catagory.Id, catagory.Name));
}
}
}
}
public class Temp{
public Category Recursive(long parentId, string name)
{
Category catagory = new Category();
catagory.Id = parentId; catagory.Name = name;
using (var db = new aaContext2())
{
//base condition
if (db.Catagory.Where(catagory1 => catagory1.ParentId == parentId).Count() < 1)
{
return catagory;
}
else
{
IList<Category> newCatagoryList = new List<Category>();
foreach (Category cat in db.Catagory.Where(cata => cata.ParentId == parentId))
{
newCatagoryList.Add(Recursive(cat.Id, cat.Name));
}
catagory.CatagoryList = newCatagoryList;
return catagory;
}
}
}
}
public class aaContext2 : DbContext
{
public DbSet<Category> Catagory { get; set; }
}
public class Category
{
public virtual long Id { get; set; }
public virtual string Name { get; set; }
public virtual Category Parent { get; set; }
public virtual ICollection<Category> CatagoryList { get; set; }
public virtual long? ParentId { get; set; }
}
Related
I'm getting the results of a sql outer join as flat results in an IEnumerable, and would like to convert them to nested typed objects in linq. From something like this:
[{id: 1, industryId: 1}, {id:1, industryId: 2}, {id:2, industryId: 1} etc..]
to something like this:
list of Company [{id: 1, list of Industry{industryId: 1, 2}, {id: 2, list of Industry{industryId: 1}}]
I'm currently trying a solution with GroupBy:
Companies = flatDbRows
.GroupBy(
row => row.CompanyId,
(key, value) => new CompanyModel
{
CompanyId = value.First().CompanyId,
CompanyName = value.First().CompanyName,
Industries = value
.GroupBy(
row => new { row.IndustryId, row.Industry },
(k, v) => new IndustryModel() { IndustryId = k.IndustryId, Name = k.Industry }
)
.Where(x => x.IndustryId != 0)
.ToList(),
}).ToList();
}
but it doesn't feel great, especially with all the value.First() I'm using to get the values that only belong to each grouped company. Is there something more appropriate? Group join sounded more like what I wanted, but I'm having trouble understanding how to apply it to a single list. I'm open to using query syntax instead of the lambdas if that's easier.
I'm trying to go from this model (where company-related info will be duplicated for each outer joined industry result):
public class CompanyFlatDbRowsModel
{
public int CompanyId { get; set; }
public string CompanyName { get; set; }
public int IndustryId{ get; set; }
public string Industry { get; set; }
}
to this:
public class CompanyModel
{
public int CompanyId { get; set; }
public string CompanyName { get; set; }
public IEnumerable<IndustryModel> Industries { get; set; }
}
// FULL edit after providing your models
public class TestClass
{
public class CompanyModel
{
public int CompanyId { get; set; }
public string CompanyName { get; set; }
public List<IndustryModel> Industires { get; set; }
}
public class IndustryModel
{
public int IndustryId { get; set; }
public string IndustryName { get; set; }
}
public class CompanyFlatDbRowsModel
{
public CompanyFlatDbRowsModel()
{
}
public int CompanyId { get; set; }
public string CompanyName { get; set; }
public int IndustryId { get; set; }
public string Industry { get; set; }
}
[Fact]
public void Test()
{
var data = new List<CompanyFlatDbRowsModel>
{
new CompanyFlatDbRowsModel
{
CompanyId = 1,
CompanyName = "Company 1",
IndustryId = 1,
Industry = "Industry 1"
},
new CompanyFlatDbRowsModel
{
CompanyId = 1,
CompanyName = "Company 1",
IndustryId = 2,
Industry = "Industry 2"
},
new CompanyFlatDbRowsModel
{
CompanyId = 2,
CompanyName = "Company 2",
IndustryId = 3,
Industry = "Industry 3"
},
new CompanyFlatDbRowsModel
{
CompanyId = 2,
CompanyName = "Company 2",
IndustryId = 4,
Industry = "Industry 4"
},
};
var result = data.GroupBy(x => x.CompanyId)
.Select(x => new CompanyModel()
{
CompanyId = x.Key,
CompanyName = x.First().CompanyName,
Industires = x.Select(y=> new IndustryModel
{
IndustryName = y.Industry,
IndustryId = y.IndustryId
}).ToList()
}).ToList();
foreach (var item in result)
{
var text = $"Company id : {item.CompanyId}, industries : {string.Join(',',item.Industires.Select(x=>$"(name: {x.IndustryName}, id: {x.IndustryId})"))}";
Debug.WriteLine(text);
}
}
}
output:
Company id : 1, industries : (name: Industry 1, id: 1),(name: Industry 2, id: 2)
Company id : 2, industries : (name: Industry 3, id: 3),(name: Industry 4, id: 4)
edit:
alternatively you can do as below, however the "first" thing still occurs somewhere, I have tried also the GroupJoin but it doesn't really help in that case.
var otherResult = data.Select(x =>
new CompanyModel
{
CompanyId = x.CompanyId,
CompanyName = x.CompanyName,
Industires = data
.Where(y => y.CompanyId == x.CompanyId)
.Select(y => new IndustryModel
{
IndustryId = y.IndustryId,
IndustryName = y.Industry
}).ToList()
})
.GroupBy(y => y.CompanyId)
.Select(x => x.First())
.ToList();
edit:
one more approach without using "first"
var anotherResult = data.GroupBy(x => x.CompanyId)
.Select(x =>
{
var companyModel = new CompanyModel()
{
CompanyId = x.Key
};
companyModel.Industires = x.Select(y =>
{
companyModel.CompanyName = y.CompanyName; // assignign here occurs multiple times however with the same value
return new IndustryModel
{
IndustryId = y.IndustryId,
IndustryName = y.Industry
};
}).ToList();
return companyModel;
}).ToList();
I have created 2 models to store the results of an sql query. Now I would like to join them for each of the week's... (week1 = Record_id, week2 = Record_id)
to get a new Object in which I would have all the data from the 1st model, as well as map data from the "Category" Model to it.
I created a new Model for it, but I am not sure how to write a linq query
First Model:
public class CustomData
{
public string full_name { get; set; }
public string location { get; set; }
public int week1 { get; set; }
public int week2 { get; set; }
public int week3 { get; set; }
}
Second Model:
public class Category
{
public int Record_ID { get; set; }
public int Color{ get; set; }
public string Name { get; set; }
}
New Model for end result:
public class WeekView
{
public string full_name { get; set; }
public string location { get; set; }
public Category week1 { get; set; }
public Category week2 { get; set; }
public Category week3 { get; set; }
}
This should work:
List<CustomData> list = new List<CustomData>();
list.Add(new CustomData() { full_name = "test", location = "test", week1 = 0, week2 = 1, week3 = 2 });
list.Add(new CustomData() { full_name = "test2", location = "test2", week1 = 0, week2 = 12, week3 = 22 });
List<Category> categories = new List<Category>();
categories.Add(new Category { Color = 0, Name = "testName", Record_ID = 0 });
categories.Add(new Category { Color = 1, Name = "testName1", Record_ID = 1 });
categories.Add(new Category { Color = 2, Name = "testName2", Record_ID = 2 });
categories.Add(new Category { Color = 3, Name = "testName3", Record_ID = 12 });
categories.Add(new Category { Color = 4, Name = "testName4", Record_ID = 22 });
List<WeekView> results = new List<WeekView>();
results.AddRange(list.Select(x=>
new WeekView() { full_name = x.full_name,
location = x.location,
week1 = categories.FirstOrDefault(c => c.Record_ID == x.week1),
week2 = categories.FirstOrDefault(c => c.Record_ID == x.week2),
week3 = categories.FirstOrDefault(c => c.Record_ID == x.week3)
}));
Try out the following:
var result = (from cd in CustomDatas
join ca1 in Categories on cd.week1 equals ca.Record_ID into ca1r
from ca1 in ca1r.DefaultIfEmpty()
join ca2 in Categories on cd.week2 equals ca.Record_ID into ca2r
from ca2 in ca2r.DefaultIfEmpty()
join ca3 in Categories on cd.week3 equals ca.Record_ID into ca3r
from ca3 in ca3r.DefaultIfEmpty()
select new {
full_name = cd.full_name,
location = cd.location,
week1 = ca1,
week2 = ca2,
week3 = ca3
}
Given the classes below, I want to be able to use a List of ids to return designs that have the AttributeId of 1 or 3 in the DesignAttribute table.
public class Design
{
public int DesignId { get; set; }
public string DesignName { get; set; }
public virtual List<DesignAttribute> DesignAttributes { get; set;}
}
public class Attribute
{
public int AttributeId { get; set; }
public string AttributeName { get; set; }
}
public class DesignAttribute
{
public int DesignAttributeId { get; set; }
public virtual Design Design { get; set; }
public virtual Attribute Attribute { get; set; }
}
A design can have 1 or more attributes, for example
Design Table
DesignId DesignName
1 Design A
2 Design B
3 Design C
Attribute Table
AttributeId AttributeName
1 Light
2 Dark
3 Demo
DesignAttribute Table
DesignAttributeId Design_DesignId Attribute_AttributeId
1 1 1 Design A is Light
2 1 3 Design A is also a Demo
3 2 2 Design B is Dark
4 3 1 Design C is Light
I've got the following code
//attributes list = "[1,3] I want any designs that have Light OR Demo attributes"
public List<Design> FilterDesigns(List<string> attributes)
{
//sudo code as i'm not sure how to structure this.
var designs = db.Designs.Where(i => i.DesignAttributes
WHERE DesignAttributes.AttributeId is in the list of attributes passed into the method)
}
So i'd hopefully end up with a list of 2 items containing the designs Design A and Design C, as they both have an ID against the Attribute Id 1 and 3 in the DesignAttribute lookup table.
Try this :
var designs = db.Designs.Where(design =>
design.DesignAttributes.Any(designAttribute =>
attributes.Contains(designAttribute.Attribute.AttributeId)))
.ToList();
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication29
{
class Program
{
static void Main(string[] args)
{
List<Design> designTable = new List<Design>() {
new Design() { DesignId = 1, DesignName = "A"},
new Design() { DesignId = 2, DesignName = "B"},
new Design() { DesignId = 3, DesignName = "C"}
};
List<Attribute> attributeTable = new List<Attribute>() {
new Attribute() { AttributeId = 1, AttributeName = "Light"},
new Attribute() { AttributeId = 2, AttributeName = "Dark"},
new Attribute() { AttributeId = 3, AttributeName = "Demo"}
};
List<DesignAttribute> designAttributeTable = new List<DesignAttribute>() {
new DesignAttribute() { DesignAttributeId = 1, DesignId = 1, AttributeId = 1},
new DesignAttribute() { DesignAttributeId = 2, DesignId = 1, AttributeId = 3},
new DesignAttribute() { DesignAttributeId = 3, DesignId = 2, AttributeId = 2},
new DesignAttribute() { DesignAttributeId = 4, DesignId = 3, AttributeId = 1}
};
var results = (from dattbl in designAttributeTable
join dttbl in designTable on dattbl.DesignId equals dttbl.DesignId
join attbl in attributeTable on dattbl.AttributeId equals attbl.AttributeId
select new { designName = dttbl.DesignName, attributeName = attbl.AttributeName }).ToList();
}
}
public class Design
{
public int DesignId { get; set; }
public string DesignName { get; set; }
public virtual List<DesignAttribute> DesignAttributes { get; set; }
}
public class Attribute
{
public int AttributeId { get; set; }
public string AttributeName { get; set; }
}
public class DesignAttribute
{
public int DesignAttributeId { get; set; }
public int DesignId { get; set; }
public int AttributeId { get; set; }
}
}
You can try to use this query:
var ids = new List<int> { 1, 3 };
var designs = db.DesignAttributes
.Where(m => ids.Contains(m.DesignAttributeId))
.Select(p => p.Design)
.ToList();
It will query DesignAttributes where DesignAttributeId are present in list ids. Than it will select Designs.
i have an issue when getting different record from related table : for example i have two table name as Tag and Product.I'm going to set tag for each product.Product table item what exits on tag table not show if this item exist on Product table.
public class Tags
{
public int TagId {get;set;}
public string Title {get;set;}
}
public class Products
{
public int Id {get;set;}
public string Title {get;set;}
}
public class ProductsTag
{
public int Id {get;set;}
public int ProductId {get;set;}
public int TagId {get;set;}
}
var tagList = List<Tags>();
tagList.Add(new Tags{TagId = 1, "Cacao"});
tagList.Add(new Tags{TagId = 2, "Banana"});
tagList.Add(new Tags{TagId = 3, "Chevy"});
tagList.Add(new Tags{TagId = 4, "Nuts"});
var productList = List<Products>();
productList.Add(new Products{Id=1, "Chocolate"});
productList.Add(new Products{Id=2, "Chocolate"});
var pTagList = List<ProductsTag>();
pTagList.Add(new ProductsTag{Id=1, ProductId=1, TagId=1});
pTagList.Add(new ProductsTag{Id=2, ProductId=1, TagId=4});
pTagList.Add(new ProductsTag{Id=3, ProductId=2, TagId=1});
foreach(var i in tagList)
{
foreach(var n in pTagList)
{
if(i.TagId!=n.TagId)
{
i.Title;
}
}
}
So what are you trying to do? When you do i.Title what are you expecting to happen?
If you're trying to find the tags that aren't in the pTagList then, as you've seen, your two foreach loops are flawed and won't do that.
Some linq will help though ...
var unusedTags = tagList
.Except(from tag in tagList
join productsTag in pTagList on tag.TagId equals productsTag.TagId
select tag);
I hope this is what you want
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<Tags> tagList = new List<Tags>();
tagList.Add(new Tags { TagId = 1, Title = "Cacao" });
tagList.Add(new Tags { TagId = 2, Title = "Banana" });
tagList.Add(new Tags { TagId = 3, Title = "Chevy" });
tagList.Add(new Tags { TagId = 4, Title = "Nuts" });
List<Products> productList = new List<Products>();
productList.Add(new Products { Id = 1,Title= "Chocolate" });
productList.Add(new Products { Id = 2,Title= "Chocolate" });
List<ProductsTag> pTagList = new List<ProductsTag>();
pTagList.Add(new ProductsTag { Id = 1, ProductId = 1, TagId = 1 });
pTagList.Add(new ProductsTag { Id = 2, ProductId = 1, TagId = 4 });
pTagList.Add(new ProductsTag { Id = 3, ProductId = 2, TagId = 1 });
List<string> missingstuff = new List<string>();
foreach (var i in tagList)
{
int index = pTagList.FindIndex(item => item.TagId == i.TagId);
if (index < 0)
{
missingstuff.Add(i.Title);
}
}
}
public class Tags
{
public int TagId {get;set;}
public string Title {get;set;}
}
public class Products
{
public int Id {get;set;}
public string Title {get;set;}
}
public class ProductsTag
{
public int Id {get;set;}
public int ProductId {get;set;}
public int TagId {get;set;}
}
}
}
I have two classes: Group and Item.
public class Group
{
public string Name{ get; set; }
public List<Item> ItemList { get; set; }
}
And then Item
public class Item
{
public int ID{ get; set; }
public string Name{ get; set; }
public string Description{ get; set; }
public Group ItemGroup {get;set;}
}
Each group show have a set of items.
The following code is meant to get the list of items of a particular group, and it works when the ItemGroup in the Items class is set to type string, but not as a type Group.
public IEnumerable<Item> GetItemByGroup(string group)
{
return repository.GetAllItems().Where(
p => string.Equals(p.ItemGroup, group, StringComparison.OrdinalIgnoreCase));
}
How to change the code to get the list of items in a group by its Name property which is set in the Group class.
And how do I set a list/collection of Items in the Group class
I think this should work. Give it a hit
public IEnumerable<Item> GetItemByGroup(string group)
{
return repository.GetAllItems().Where(p =>p.ItemGroup.Name.Equals(group));
}
Update
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
List<Item> list = new List<Item>();
Item i = new Item()
{
ID = 1,
Name = "Amit",
Description = "Test",
ItemGroup = new Group() { Name = "A" }
};
list.Add(i);
i = new Item()
{
ID = 2,
Name = "Amit1",
Description = "Test1",
ItemGroup = new Group() { Name = "A1" }
};
list.Add(i);
i = new Item()
{
ID = 3,
Name = "Amit11",
Description = "Test11",
ItemGroup = new Group() { Name = "A11" }
};
list.Add(i);
i = new Item()
{
ID = 4,
Name = "Amit111",
Description = "Test111",
ItemGroup = new Group() { Name = "A111" }
};
list.Add(i);
i = new Item()
{
ID = 9,
Name = "Amit4a",
Description = "Test4a",
ItemGroup = new Group() { Name = "A111" }
};
list.Add(i);
i = new Item()
{
ID = 5,
Name = "Amit5",
Description = "Test5",
ItemGroup = new Group() { Name = "A111" }
};
list.Add(i);
i = new Item()
{
ID = 6,
Name = "Amit6",
Description = "Test6",
ItemGroup = new Group() { Name = "A111" }
};
list.Add(i);
var list1 = list.Where(p => p.ItemGroup.Name.Equals("A111"));
// Console.Write(list1.Count());
foreach (var item in list1)
{
Console.WriteLine(string.Format("ID: {0} Name: {1} Description: {2} Group: {3}",item.ID,item.Name,item.Description,item.ItemGroup.Name));
}
Console.Read();
}
}
public class Group
{
public string Name { get; set; }
}
public class Item
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public Group ItemGroup { get; set; }
}
}