How to get hierarchical organisational data using LINQ? - linq

I have some organisation tables which are linked to an OrgUser table.
OrgUser >- Org -< OrgLink
-<
There are 2 1toMany links to OrgLink with one being ParentOrg and the other be ChildOrg.
So a typical example would be Joe Bloggs who works in the "Small Business Unit" which is part of the "Business Department".
There is a record in OrgLink which points "Business Department" to its child org of "Small Business Unit" which has an OrgUser called "Joe BLoggs".
If I am logged in as "Joe Bloggs" then I would like to get a list of all the immediate and parental orgs that he is linked to, so in this case I would hope to get "Small Business Unit" and "Business Department". I can get the immediate org, but the parent bit is confusing me. Also if there is no parent then just the immediate org should be returned. Basically all orgs linked to the immediate org should be returned.
My LINQ so far:
from SOU in StdOrgUser
join SO in StdOrg on SOU.StdOrgId equals SO.Id
where SOU.UserId.Equals(new Guid("42995B01-97C8-4148-8EA3-5CCC55535194"))
select new { OrgName=SO.Name, Col2= SOU.UserId, c3=SO.StdOrgType.Name}
Many thanks in advance.
EDIT/UPDATE:
Having researched this I have found that I do not need the JOIN or INCLUDE since my EF model has the required associations and therefore appear as navigational properties. I ended up using a UNION with 2 LINQ queries, thus the pseudocode is:
var results1 = Get child organisation that UserId works for.
var results2 = Get parent organisation for child organisation if it exists.
var results3 = results1.Union(results2)
foreach org in results3
{
console.writeline(org.Id);
console.writeline(org.Name);
}
I am sure there is a more eloquent approach, and do feel free to suggest, but this approach does work. Perhaps when my knowledge of LINQ get better I will find it myself!

Related

LINQ Include vs Join. Are they equivalent?

I have used join in linq to join 2 tables. What is the difference between a join and Include. From what I see, they both behave the same.
Include vs. Join
An Included is intended to retain the original object structures and graphs. A Join is needed to project a flattened representation of the object graph or to join types which are not naturally related through the graph (ie. join the customer's city with a shipping facility's city).
Compare the following:
db.Customers.Include("Orders")
Generates an IEnumerable each of which may contain their corresponding list of Orders in an object graph like this:
Customer 1
Order
Order
Order
Customer 2
Order
Order
In contrast, if you do the same with a join projecting into an anonymous type you could get the following:
from c in db.Customers
join o in db.Orders on c.CustomerId equals o.CustomerId
select new {c, o}
This produces a new IEnumerable<Anonymous<Customer, Order>> where the customer is repeated for each order.
{ Customer1, orderA }
{ Customer1, orderB }
{ Customer1, orderC }
{ Customer2, orderD }
{ Customer2, orderE }
{ Customer2, orderF }
While both may issue the same request to the database, the resulting type may be quite different.
In a sense, yes. Include is implemented as a join. Depending on the nullability of the included link it is an inner or left join.
You can always build an include yourself by using a join, like this:
db.Users.Select(u => new { u, u.City })
This is an "include" for the user's city. It manifests itself as a SQL join.
If you simply need all Orders for some Customers. Good example here for blog application is displaying all Comments below Articles always. Then Include is your way of work.
Join in opposition is more helpful if you need some Customers and filters out them using some data contained in Orders entity. For example you want to sort out Articles to send to the Police Articles with Comments containing vulgar words.
Also if your Orders entity contains a lot of data (many columns) taking a lot of memory and you don't need all of them then join can be much more efficient but here always is a question what "lot of data" or "many columns" means so test first will be the best choice.

Linq related items not loading

I have a "task" table, which has a "sub category". The sub category is related to a Category. A category has many sub categories, but my task item only stored the sub category id (The category can be deduced from this).
So, my entity framework seems to understand this relationship.
But, my link is failing.
public TaskObject GetTask(int taskId)
{
var item = (from t in _te.tasks.Include("r_sub_category").Include("r_category").Include("r_priority").Include("r_state").Include("assigned_person").Include("create_person").Include("update_person") where t.task_id == taskId select t).FirstOrDefault();
return Transformer.UnpackTask(item);
}
There is a r_category table, and entity object, but when I run this, it tells me:
A specified Include path is not valid. The EntityType 'taskerModel.task' does not declare a navigation property with the name 'r_category'.
And that's correct - r_category is linked to my r_sub_category table... and not directly to task. Is there a way to load the r_category?
Or, maybe this Include is lazy, and I should be doing some sort of Joining myself? Maybe more efficient?
You need to show the full path with dot Notation so im guessing it would be
"r_sub_category.r_category".
And so forth

Using lookup values in linq to entity queries

I'm a total LINQ noob so I guess you'll probably have a good laugh reading this question. I'm learning LINQ to create queries in LightSwitch and what I don't seem to understand is to select an entity based on a value in a lookup table. Say I want to select all employees in a table that have a job title that is picked from a related lookup table. I want the descriptive value in the lookup table for the user to pick from a list to use as a parameter in a query, not the non-descriptive id's.
Can someone point me to an article or tutorial that quickly explains this, or give me a quick answer? I AM reading books and have a Pluralsight account but since this is probably the most extensive knowledge I will need for now a simple tutorial would help me more that watching hours of videos and read thousands of pages of books.
Thanks in advance!
Edit: this is the code. As far as I know this should but won't work (red squigly line under EmployeeTitle, error says that EmployeeContract does not contain a definition for EmployeeTitle even though there is a relationship between the two).
partial void ActiveEngineers_PreprocessQuery(ref IQueryable<Employee> query)
{
query = from Employee e in query
where e.EmployeeContract.EmployeeTitle.Description == "Engineer"
select e;
}
Edit 2: This works! But why this one and not the other?
partial void ActiveContracts_PreprocessQuery(ref IQueryable<EmployeeContract> query)
{
query = from EmployeeContract e in query
where e.EmployeeTitle.Description == "Engineer"
select e;
}
The red squiggly line you've described is likely because each Employee can have 1-to-many EmployeeContracts. Therefore, Employee.EmployeeContracts is actually an IEnumerable<EmployeeContract>, which in turn does not have a "EmployeeTitle" property.
I think what you're looking for might be:
partial void ActiveEngineers_PreprocessQuery(ref IQueryable<Employee> query)
{
query = from Employee e in query
where e.EmployeeContract.Any(x => x.EmployeeTitle.Description == "Engineer")
select e;
}
What this is saying is that at least one of the Employee's EmployeeContracts must have an EmployeeTitle.Description == "Engineer"
Try something like this:
partial void RetrieveCustomer_Execute()
{
Order order = this.DataWorkspace.NorthwindData.Orders_Single
(Orders.SelectedItem.OrderID);
Customer cust = order.Customer;
//Perform some task on the customer entity.
}
(http://msdn.microsoft.com/en-us/library/ff851990.aspx#ReadingData)
Assuming you have navigation properties in place for the foreign key over to the lookup table, it should be something like:
var allMonkies = from employee in context.Employees
where employee.EmployeeTitle.FullTitle == "Code Monkey"
select employee;
If you don't have a navigation property, you can still get the same via 'manual' join:
var allMonkies = from employee in context.Employees
join title in context.EmployeeTitles
on employee.EmployeeTitleID equals title.ID
where title.FullTitle == "Code Monkey"
select employee;

Linq: Polymophic entity fetch in select list

I want to do the following...
FROM o IN orders
SELECT new OrderContainer { Contact = (PostalContact) o.Contact }
So hopefully you can see that the order's 'Contact' will be of a derived type. Unfortunately however it doesn't seem to do a polymorphic fetch! Is there anyway of achieving this?
Cheers, Ian.
Try using the extention method .OfType()
from o in orders
select new OrderContainer { Contact = o.Contact.OfType<PostalContact>().FirstOrDefault() }
Edit:
a way to get the full object data, but i doubt that this is good enough for your needs.
from c in contacts.OfType<PostalContact>()
where c.Orders.Any(o=>o.Contact.Id == c.id)
select new OrderContainer { Contact = c }
on the other hand, if you set the base class (entity) to abstract, you may find that entity will load the full objects. but this is not recomended due to the queries that are generated. if you are looking into this you may want to look at (TPH) Table per Hierarchy for your contacts

Concatenating lists inside a LINQ query

My data structure is set up this way
A user takes a number of modules
A module contains a number of courses
Here's how the relationship looks like:
How do I get a list of courses the user takes?
The query I have now is:
var courses = (from ClassEnrollment enrolment in entities.ClassEnrollment
where enrolment.UserID == UserID
join Module module in entities.Module
on enrolment.ModuleID equals module.ID
select module.Course
).ToList();
However, this doesn't result in a list of courses, but rather a list of list of courses.
How can I flatten this query to a list of distinct courses?
According to your data structure screenshot, you have a one-to-many relationship between the ClassEnrollment and Module, as well as navigational property called Module. You also have a many-to-many relationship between Module and Course, but the navigational property should be called Courses. Given your code, you want something like this:
var courses = entities.
ClassEnrollment.
Where(e => e.UserID == UserID).
SelectMany(e => e.Module.Courses).
ToList();
Your question, however, mentions a user: A user takes a number of modules, How do I get a list of courses the user takes?. I don't see any User entity anywhere else, though, so it would be nice if you could clarify. Are you using LINQ-to-SQL, btw?
Something like this:
var courses = from ClassEnrollment enrolment in entities.ClassEnrollment
from module in entities.Module
where enrolment.ModuleID equals module.ID && enrolment.UserID equals UserID
select module.Course
Use SelectMany.
You can use
courses.SelectMany(c => c);
In your query you don't need explicitly specify the type for the range variables
Or you can join course to the query
var query = from enrolment in entities.ClassEnrollment
join module in entities.Module on enrolment.ModuleID equals module.ID
join course in entities.Course on module.CourseID equals course.ID
where enrolment.UserID == UserID
select course;
var course = query.ToList();

Resources