LINQ Weirdness with joining tables - linq

I have to join multiple tables. The tables have similar data for each table.
ID
(table id for FK)
Name
Description
Owner
from d in Departments
join f in Functions on d.DepartmentID equals f.DepartmentID
join pg in Processes on f.FunctionID equals pg.FunctionID
select new { d.DepartmentID, f.Name, pg.Name }
This throws an error 'An anonymous type cannot have multiple properties with the same name'
is there a better way to join these tables?
Should I do Select new { d, f, pg } ? Is it easy to grab the data from that?
I am very new to LINQ so any help is appreciated.

The compiler creates the properties of the anonymous type based on the property you use. In your case you use the property Name twice. Once in f.Name and once in pg.Name.
To fix it you have to specify at least one of the two property names explicitly:
select new { d.DepartmentID, FunctionName = f.Name, ProcessName = pg.Name }

You just need to give unique names for the two Name properties. Something like:
from d in Departments
join f in Functions on d.DepartmentID equals f.DepartmentID
join pg in Processes on f.FunctionID equals pg.FunctionID
select new { d.DepartmentID, FName = f.Name, PGName = pg.Name }
When you don't specify your own names, the compiler will just use the full name of the property, but since in this case they are both just Name, it will generate an error.

Related

Using query hints to use a index in an inner table

I have a query which uses the view a as follows and the query is extremely slow.
select *
from a
where a.id = 1 and a.name = 'Ann';
The view a is made up another four views b,c,d,e.
select b.id, c.name, c.age, e.town
from b,c,d,e
where c.name = b.name AND c.id = d.id AND d.name = e.name;
I have created an index on the table of c named c_test and I need to use it when executing the first query.
Is this possible?
Are you really using this deprecated 1980s join syntax? You shouldn't. Use proper explicit joins (INNER JOIN in your case).
You are joining the two tables C and D on their IDs. That should mean they are 1:1 related. If not, "ID" is a misnomer, because an ID is supposed to identify a row.
Now let's look at the access route: You have the ID from table B and the name from tables B and C. We can tell from the column name that b.id is unique and Oracle guarantees this with a unique index, if the database is set up properly.
This means the DBMS will look for the B row with ID 1, find it instantly in the index, find the row instantly in the table, see the name and see whether it matches 'Ann'.
The only thing that can be slow hence is joining C, D, and E. Joining on unique IDs is extremely fast. Joining on (non-unigue?) names is only fast, if you provide indexes on the names. I'd recommend the following indexes accordingly:
create index idx_c on c (name);
create index idx_e on e (name);
To get this faster still, use covering indexes instead:
create index idx_b on b (id, name);
create index idx_c on c (name, id, age);
create index idx_d on d (id, name);
create index idx_e on e (name, town);

ORA-00918 returns from stored procedure but it works executing a query in SQL Page

I'm trying return a list from db but it gives me Error "ORA-00918: column ambiguously defined".
When I execute this query inside new SQL page, it returns true list. However, when I write it in a package as stored procedure, it returns ORA-00918 and package goes invalid status.
What is the reason for this difference?
select distinct c.customer_no, m.title, c.group_id, g.name, c.pricelist_id, p.name from db.customer c
join db.pricelist p on c.pricelist_id = p.pricelist_id
join db.master m on c.customer_no = m.customer_no
join db.group g on c.group_id = g.id
where (c.customer_no = pn_customer_no or pn_customer_no=-1)
and (c.group_id = pn_group_no or pn_group_no=-1)
and (c.pricelist_id = pn_pricelist_no or pn_pricelist_no=-1)
and (c.kom_type = ps_kom_tip)
order by c.customer_no asc
You are selecting the columns:
select distinct
c.customer_no,
m.title,
c.group_id,
g.name, -- NAME column
c.pricelist_id,
p.name -- NAME column
When you run the query in SQL/Plus or SQL Developer (or another IDE) it will output the columns:
CUSTOMER_NO TITLE GROUP_ID NAME PRICELIST_ID NAME1
and will rename the second NAME column to NAME1.
In the PL/SQL scope, it will not do this and will try to handle the two columns with the names you have given (i.e. the same names), fail and return ORA-00918.
You need to give one (or both) column an alias so they have distinct names.
New SQL page assigns your dublicate columns new temporary column names.
But stored procedures add your values a list matched column names.
Therefore, two columns have same names, it confuses which name should desired name.
Like bundle, your column name will be key to learn value and value will be value.
You should change one of them p.name or g.name or both of them.
select distinct c.customer_no, m.isim_unvan, c.group_id, g.name as groupName, c.pricelist_id, p.name as tarifeName from db.customer c
join db.pricelist p on c.pricelist_id = p.pricelist_id
join db.master m on c.customer_no = m.musteri_no
join db.group g on c.group_id = g.id
where (c.customer_no = pn_customer_no or pn_customer_no=-1)
and (c.group_id = pn_group_no or pn_group_no=-1)
and (c.pricelist_id = pn_pricelist_no or pn_pricelist_no=-1)
and (c.kom_type = ps_kom_tip)
order by c.customer_no asc

LINQ: Inner join to the First row in a sub query?

I have two classes, basically one holds Members and the other Sessions.
They are joined together with a common field called "name". There is one member but can be many Sessions.
So if I do a standard join I get back 1 member and many sessions. I just want to get back the first row of sessions.
The session has field called SessioEndTime. So I need to order by DESC on this to pick out the first record.
This is my linq; I have returns too many. I think I need a subquery but I am a little confused.
var sessions = from m in this.members
join s in this.sessions
on m.Name equals s.Name
select new { MemberName = m.Name, SessionTime = s.SessioEndTime};
Edit
To make it clear, imagine I have five members, each member has NUMEROUS sessions. I just wish to receive my five members but with only one session each, that session is the LATEST session which can be got from the SessioEndTime.
Try this:
var sessions =
from m in this.members
join s in
(
from se in this.sessions
group se by se.Name into g
select new {Name = g.Key, SessioEndTime = g.Max(a=>a.SessioEndTime)}
)
on m.Name equals s.Name
select new { MemberName = m.Name, SessionTime = s.SessioEndTime}

LINQ where clause

I have the following linq query
var ret = from u in MenuHeaders
.Include("MenuHeaderItems.MenuItem")
select u;
I need to select ONLY menu headers which exist for certain users, which belong to a certain role given a user id.
So, the relational path would be something like this...
MenuHeader RoleMenuHeaders Roles UserRoles Users
---------- --------------- ----- --------- -----
ID <---MenuHeaderID |-> ID <---| UserID----->ID
RoleID -------| |-- RoleID
How do I get my above query to only return MenuHeaders where UserID=1?
If you're using LINQ to Entities, this relationship is probably automatically mapped via properties, and (assuming these are many-to-many relationships, as they appear to be in the schema you show) you can take advantage of the Any operator:
var ret = from mh in MenuHeaders.Include("MenuHeaderItems.MenuItem")
where mh.Roles.Any(r => r.Users.Any(u => u.UserId == 1))
select mh;
Well, you could do it with a join:
var ret = from mh in MenuHeaders.Include("MenuHeaderItems.MenuItem")
join ur in UserRoles on mh.RoleID equals u.RoleID
where ur.UserID == 1
select mh;
(I don't know whether you need Include("UserRoles.UserRole") or anything like that. I don't know which LINQ provider you're using.)
Adding a where clause that references a joined table modifies the resultant query and invalidates the Include.
Check this out.
How to make an Include really include.

Join in linq: "The specified LINQ expression contains references to queries that are associated with different contexts."

Is it possible to make a join in linq and only return data from one dataset where the other key was present, a little like:
var q = from c in customers
join o in orders on c.Key equals o.Key
select new {c.Name, o.OrderNumber};
and then instead of returning just the two records then returning customers like:
var q = from c in customers
join o in orders on c.Key equals o.Key
select c;
When I try to do (something similar) I get this error:
The specified LINQ expression contains references to queries that are associated with different contexts.
I going to assume that you've skipped a Where clause which involved the orders table (or otherwise the join would be pointless)
In which case, you can just have Linq infer the join.
var q = from c in customers
where c.Orders.Any(o=> o.ProductCode == productCode)
select c;
Linq2Sql will automatically create the Orders property if you have a foreign key defined; I believe with the Entity Framework, you have to manually specify it.
The error indicates an other problem:
You have to use the same DataContext on every object in the query if you're using Linq to SQL.
Your code should look somehow like that:
using (MyDataContext dc = new MyDataContext())
{
var q = from c in dc.customers
join o in dc.orders on c.Key equals o.Key
select c;
// process q within the DataContext
// the easies would be to call q.ToList()
}
Will it be in EF 4.0 to create join from multiple context?
For example:
TestModelEntities e1 = new TestModelEntities();
TestModelEntities e2 = new TestModelEntities();
var d = from firme1 in e1.firme
join g in e2.grad on firme1.grad.grad_id equals g.grad_id
select firme1;

Resources