I need to build a Org Chart that prints from a web page and I have something like 19 to 32 entities on the second level and 3-7 entities on the third level.
I tried a solution called OrgChart component from Team Improver at
http://www.orgchartcomponent.com/default.aspx
but they are in England and don't respond to their email.
I also tried a solution from
https://www.codeproject.com/Articles/18378/Organization-Chart-Generator
that has the basic tree org chart.
I populate from a database via Ling to SQL, No Problem.
Parent Entity - Level 1
|
|
---Child Entity Level 2
|
|
---Child Entity Level 2
|
|
---Child Entity Level 2
|
|
---Child Entity Level 2
|
|
---Child Entity Level 2
|
|
---Child Entity Level 2
|
|
Child Entity Level 3
|
|
Child Entity Level 3
|
|
Child Entity Level 3
|
|
Child Entity Level 3
// using recursive function.
static void Get_Geneology(Employee manager, int Level = 0) // find all genealogy (kid to great grandkids or employee under a manager down the pyramid)
{
string indentLines = new string(' ', Level * 2);
var managedEmployees = Employees.Where(e => e.Manager_ID == manager.Emp_ID); // 1st call. look all employees under a Manager. or all kids of a father.
Console.WriteLine($"{indentLines} {Level + 1}-{manager.FirstName}{(managedEmployees.Count() > 0 ? "*" : "")}"); // with * after name mean that person manage sombody or father have kid(s)
foreach (var employee in managedEmployees) Get_Geneology(employee, Level + 1); // recursive, find all under under (to the deapest of each people geneology for each manager)
}
Related
I have the following 3 table definitions in my SQL Server database:
+----------------------------------+-----------------+------------------------------------------------
| Product | Rating | Image |
+----------------------------------+-----------------+-------------------------------------------------
| ProductId | Id | Id |
| ProdctName | Rating | Image |
| | ProductId FK References(Product)| ProductId FK References(Product)|
+----------------------------------+-----------------+---------------+----------------------------------
And these tables contain the following sample data:
+----------------------------------+------------
|Product | ProductId |ProductName |
+----------------------------------+------------
| | 1 |Prodcuct 1 |
| | 2 |Prodcuct 2 |
| | 3 |Prodcuct 3 |
| | 4 |Prodcuct 4 |
+----------------------------------+------------+
+----------------------------------+----------------------+
|Rating | Id |RatingVal |ProductId |
|+----------------------------------+-----------------------
| | 1 |3 |1 |
| | 2 |2 |2 |
| | 3 |3 |2 |
| | 4 |5 |3 |
| | 5 |4 |3 |
+---------------------+------------+------------+----------+
+----------------------------------+----------------------+
|Image | Id |ImagePath |ProductId
+----------------------------------+-----------------------
| | 1 |ABC |1 |
| | 2 |XYZ |2 |
| | 3 |LMN |3 |
| | 4 |PQR |4 |
+---------------------+------------+------------+----------+
I need to gather information about a product in one place, such that each product contains the details about product ( from products table), related average rating ( from ratings table)m and the image path for the product ( from Image table). In other words I need the following output:
+----------------------------------+--------------------------------+
|Output | ProductId |ProductName |Avg(Rating)|ImgPath|
+----------------------------------+--------------------------------+
| | 1 |Prodcuct 1 |3 |ABC |
| | 2 |Prodcuct 2 |2.5 |XYZ |
| | 3 |Prodcuct 3 |4.5 |LMN |
| | 4 |Prodcuct 4 |0.0 |PQR |
+----------------------------------+------------+-----------+-------+
I am using Entity Framework to fetch this data, and entities in context class in my code( shown below).
My question is: How do I produce my desired output for all the products.
My code below is not able to get all the data I want. The problem is that the product with id4 is not shown in the result, I assume this is be cause product 4 does not have an entry in the ratings table.
var trendingProducts = (from ratings in entities.Rating
group ratings by new { ratings.productId } into c
join products in entities.Products on c.FirstOrDefault().productId equals products.ProductID
join images in entities.Images on c.Key.productId equals images.ProductId
select new ProductViewModel
{
ProductId = products.ProductId,
ProductName = products.ProductName,
RatingVal = c.Average(l => l.RatingVal) == null ? 0 : c.Average(l => l.Rating),
ImagePath = images.ImagePath,
}).ToList();
So you have a table of Products, a table of Ratings and a table of Images.
Every Product has zero or more Ratings, every Rating belongs to exactly one Product using foreign key ProductId. Similarly, every Product has zero or more Images, every Image belongs to exactly one Image, using foreign key ProductId. Just standard one-to-many relations.
It might be that every Product has zero-or-one Image: in that case you have a zero-or-one-to-one relation. The code will be similar. The main difference is that 'Product' won't have a collection of Images, it will only have one virtual Image.
If you follow the entity framework code first conventions you'll have classes like:
class Product
{
public int Id {get; set;}
// every Product has zero or more Ratings:
public virtual ICollection<Rating> Ratings {get; set;}
// every product has zero or more Images:
public virtual ICollection<Image> Images {get; set;}
... // other properties
}
class Rating
{
public int Id {get; set;}
// every Rating belongs to exactly one Product using foreign key:
public int ProductId {get; set;}
public virtual Product Product {get; set;}
...
}
class Image
{
public int Id {get; set;}
// every Image belongs to exactly one Product using foreign key:
public int ProductId {get; set;}
public virtual Product Product {get; set;}
...
}
This is everything entity framework needs to know to detect your one-to-many relations. It knows which tables / columns you want, and it knows the relations between the tables. It might be that you want different identifiers for your tables or properties. In that case you'll need attributes or fluent API. But that is out of scope of this question.
Note that in entity framework all non-virtual properties will become columns in your tables. All virtual properties represent the relations between the tables.
I need to gather information about a product in one place, such that
each product contains the details about product ( from products
table), related average rating ( from ratings table) and the image
path for the product (from Image table).
Whenever people query for "objects with their sub-object" they tend to create a (group)join. However, if you use entity framework it is much easier to use the ICollections for these queries. If you use an ICollection, Entity Framework will know that a (group)join is needed.
var result = myDbContext.Products // from the collection of Products
.Where(product => ...) // select only those Products that ...
.Select(product => new // from every remaining Product make one new
{ // object with the following properties:
// Select only the properties you actually plan to use!
Id = product.Id,
Name = product.ProductName,
...
AverageRating = product.Ratings // from all Ratings of this Product
.Select(rating => rating.Rating) // get the Rating value
.Average(), // and Average it.
Images = product.Images // from all Images of this product
.Select(image => image.ImagePath) // select the ImagePath
.ToList(),
// or if a Product has only zero or one Image:
Image = product.Image?.ImagePath // if the product has an Image, get its ImagePath
// or use null if there is no Image
});
The nice thing about using the ICollections is that the code is simplere and more natural, it looks more similar to the text of your requirement than a (group)join. Besides, if more than two tables are involved (group)joins tend to look horrible.
I won't try to give a solution using a GroupJoin. I'm sure other answers will show this. Compare and see for yourself which solution seems easier to understand.
I have two tables, one an invoice table and the other a hierarchy table for the accounts on the invoice
Invoice Table:
| InvoiceNo| AccNo| InvoiceAmount |
--------------------------------------
| A1234| 345| 100.00 |
| A1235| 346| 95.00 |
| A1236| 347| 15.50 |
| A1237| 348| 20.10 |
Hierarchy Table
| AccNo| HierAccNo| Level|
--------------------------------------
| 123| | 1 |
| 789| 123| 2 |
| 890| 123| 2 |
| 345| 789| 3 |
| 346| 789| 3 |
| 347| 890| 3 |
| 348| 890| 3 |
What I'm trying to do is to roll up the amounts from the invoice table to the highest level AccNo which is Level1 and then on a seperate instance from the highest account number roll back down to the next levels.
So far I am able to roll up to the highest band number by the following :
var BandL2 = from invoice in db.Invoices//Roll up to level 2
join ban in db.HierarchyTable
on invoice.AccNo equals ban.Ban
where invoice.GlobalInvoiceID == globalInvoice.Id
group invoice by ban.HierAccNo into bandHierarchy
select new
{
Level2Band = bandHierarchy.Key,
Amount = bandHierarchy.Sum(m=> m.InvoiceAmount)
};
var bandHierarchyTable = db.HierarchyTable.AsQueryable();
var BandL1 = from band2 in BandL2 // Roll Up to level 1
join band1 in bandHierarchyTable
on band2.Level2Band equals band1.Ban
group band2 by band1.HierAccNo into bandL1
select new
{
Level1Band = bandL1.Key,
Amount = bandL1.Sum(m => m.Amount)
};
But now I'm having an issue reversing the process and drilling down from Level 1 as the only details from the form is the AccNo of Level 1(eg. 123).
I'm trying to do this on the fly using pop up modals as I'm drilling.
How do I drill down again so that I can get level by level amounts?
Example:
Ouput Table from Above Code
| AccNo| Amount|
--------------------------------------
| 123| 230.60 |
Then
| AccNo| Amount|
--------------------------------------
| 789| 195 |
| 890| 35.60|
And then clicking on one of the AccNo.
| AccNo| Amount|
--------------------------------------
| 345| 100|
| 346| 95 |
Thanks!
Looks like only leaf accounts can have invoices attached to it, so get the account number, check if it is leaf account, if it is leaf it should be something like that;
var hierAccNo = 123;
var details = from invoice in db.Invoices
join ban in db.HierarchyTable
on invoice.AccNo equals ban.Ban
where invoice.GlobalInvoiceID == globalInvoice.Id
and ban.HierAccNo = HierAccNo;
if it is not leaf you want your original query on level 1 I guess to get the subtotals.
var BandL2 = from invoice in db.Invoices//Roll up to level 2
join ban in db.HierarchyTable
on invoice.AccNo equals ban.Ban
where invoice.GlobalInvoiceID == globalInvoice.Id and ban.HierAccNo = hierAccNo // dont skip this
group invoice by ban.HierAccNo into bandHierarchy
select new
{
Level2Band = bandHierarchy.Key,
Amount = bandHierarchy.Sum(m=> m.InvoiceAmount)
};
I'm kind of new to this but I'll try to give as much detail as possible. This is my SQL table.
Customers
Customers_Id (PK) | First | Last | Address | Phone | Tech_Id (FK) |
-------------------+-------+-------+--------------+----------+--------------+
1 | Bob | Smith | 123 Fake St. | 3298492 | 1 |
2 | John | Man | 123 Noe St. | 2930482 | 1 |
3 | Tom | Lee | 123 Polk St. | 9308523 | 2 |
...
Tech
Tech_Id (PK) | First | Last | Phone | Customer_Count |
--------------+-------+-------+---------+----------------+
1 | Tim | Bo | 9384027 | |
2 | Andy | Wong | 9374927 | |
3 | Jack | Help | 2183847 | |
...
I'm trying to find the best way to count how many customer that each tech has either using SQL Query or C# coding. I was thinking of doing query with Count and then insert into the Customer_Count in Tech table.
I'm using visual studio 2012 and SQL is created locally in visual studio. Please help!
You can do it through SQL - using a GROUP BY clause to group the result by each tech. You can use the COUNT function to return the number of customers assigned to each tech. You can put this in an UPDATE statement to update the customer_count field in the tech table for each tech.
For example:
UPDATE t
SET t.customer_count = COUNT(c.customer_id)
FROM tech t
INNER JOIN customers c ON c.tech_id = t.tech_id
GROUP BY c.tech_id
Remove the Customer_Count column from the tech table. It's best not to make columns which duplicate available data unless there's a valid performance reason. If you want it displayed as such, then create a view:
SELECT t.tech_id,
t.first,
t.last,
t.phone,
(SELECT COUNT(c.customer_id)
FROM customers c
WHERE c.tech_id = t.tech_id) AS Customer_Count
FROM tech t
Now you can query it like a table, but you're not tasked with maintaining data which is always up to date through this view.
I prefre to using Sql ,but failed...Disappionted..
But I am sure that you can use Ado.net to do this job.
Here is C# demo code.
//query from db use C#
var allCus = new List<Customers>();
var gps = allCus.GroupBy(w => w.Tech_Id);
foreach(var gp in gps) {
var techId = gp.Key;
var cnt = gp.Count();
//update Tech set Customer_Count = cnt where Tech_Id = techId
}
Here is Sql version
update Tech set Customer_Count = (select IdAndCnt.cnt from (select Tech_Id,count (Tech_id) as cnt from Customers group by Tech_Id ) as IdAndCnt where Tech.Tech_Id = IdAndCnt.Tech_Id)
Holp it works.
I am creating a web page that will be run once a day to send email notices to supervisors. I want each supervisor to get a single email that contains data about all of their employees, of which might have multiple events.
I have some data like this:
supervisorEmail | employeeID | eventDate | eventDetails
===================================================================================================
george#blah.org | jones | 2014-03-18 | Watch a movie
george#blah.org | jones | 2014-03-20 | Convention registration
george#blah.org | smith | 2014-03-20 | Convention registration
george#blah.org | smith | 2014-03-20 | Convention registration
gayle#blah.org | nloya | 2014-03-13 | some other stuff
gayle#blah.org | nloya | 2014-03-25 | this and that
I start by retrieving all the above data and put into a DataTable.
Next I need to group by supervisor so each gets an email.
Within each email I need the rows filtered for that supervisor. I see how LINQ can be used for some of this. I'm lost at the moment for all of it. Could I get a shove in the right direction at least?
You can group the data by supervisorEmail:
var groups = data.GroupBy(d => d.supervisorEmail);
foreach(var g in groups)
{
SendEmail(g.Key, g); // g is an IEnumerable<some type> with the data for that supervisor
}
public void SendEmail(string supervisorEmail, IEnumerable<some type> data)
{
// send data to supervisor
}
My app in ASP.NET C#. I use Linq to Sql, look the picuture
// 5 data talbe :
// Unit table
id | name | unit_type_id Unit_type
-------------------------
1 | Unit 1 | 1 id | name
2 | Unit 2 | 1 -------------
3 | Unit 3 | 1 1 | Type 1
4 | Unit 4 | 2 2 | Type 2
5 | Unit 5 | 1 3 | Type 3
6 | Unit 6 | 3
//Tool table // tool_type table
id | name | tool_type_id id | name
---------------------------- -------------------
1 | Tool 1 | 1 1 | Tool_type 1
2 | Tool 2 | 2 2 | Tool_type 2
3 | Tool 3 | 1 3 | Tool_type 3
4 | Tool 4 | 2
5 | Tool 5 | 3
//unit_tool table
unit_id | tool_id
---------------
1 | 1
2 | 1
1 | 2
1 | 3
2 | 2
2 | 3
3 | 3
3 | 2
I want to use linq to sql in C# to get data like
// Table data i want to get
Unit name | Unit type name | Tool name
-------------------------------------------------
Unit 1 | Type 1 | tool 1, tool 2, tool 3
Unit 2 | Type 1 | tool 1, tool 2, tool 3
Unit 3 | Type 1 | tool 2, tool 3
Unit 4 | Type 2 |
Unit 5 | Type 1 |
Unit 6 | Type 3 |
My code be low
// Create new class
public class unit_list
{
//Unit name
public string unit_name { get; set; }
// Unit type name
public string unit_type_name { get; set; }
// Tool name
public string tool_name { get; set; }
}
// Function get data
protected void show_unit()
{
// Create datacontext
for_testDataContext db = new for_testDataContext();
//Query data
IQueryable<unit_list> CourseList = from cl in db.units
select new unit_list()
{
unit_name = cl.name,
unit_type_name = cl.unit_type.name,
tool_name = // how to get data like "tool1, tool 2, tool 3"
};
}
You should be able to write something like this (assuming all the relationships are set up correctly in Linq):
select new unit_list()
{
unit_name = cl.name,
unit_type_name = cl.unit_type.name,
tool_name = string.Join(", ",
cl.unit_tools.Select(ut => ut.tool.name).ToArray()
)
};
In other words..
Get the one-to-many relationship to unit_tools
Select the corresponding row in tool and select the name column
Join to get a single comma-separated string
You don't have any foreign keys set up, which means you don't get automatic "navigation properties" with your mapped entities. You will have to either update your database and then regenerate the mapping, or add them yourself using the toolbox.
EDIT:
Okay, let's run down a very short checklist.
Are primary and foreign keys set and associated properly in the schema (your database)? This is important, as this is what the
sqlmetal executable uses to generate your object context.
Do the associations in your model point to the correct properties in the parent and child entities? You can check this by clicking on
an association between two objects in the model viewer and then expanding the Properties
pane. Expand the Child and Parent properties and verify they are not
empty.
If you've done everything right so far, clicking on the association between Unit_Tool and Unit should show a Child property called Units.
If you're missing an association, you can add one by:
Clicking on the Association tool in the Toolbox.
Clicking on the object which defines the primary key.
Clicking on the object that holds the foreign key.
This will bring up a dialog box that should be pretty self-explanatory.
HTH.
EDIT:
Solved this by playing around with your existing code (thanks for the upload). The problem was super simple, but not exactly obvious: you need to have an identifier column in each table, or Linq-to-SQL doesn't create the child collection reference in the data context. So, since you're using unit_tool as just a pivot table (perfectly acceptable), without a unique ID on each row, you don't get a "navigation property." To fix this, just add a primary key field (you don't ever have to actually use it - it's just for the ORM) to the unit_tool table, recreate the entity mapping, and viola!, your query will work as-is.
I have to say, this wasn't obvious at first blush. I haven't ever had this problem, since I always create a unique identifier out of habit...