How do I query a join table in EF Code First? - c#

I have a many to many relationship between tables A and B.
Since I used code first, the DB table 'AB' was automatically created. I don't have an entity model for it.
How can I, for example, query all the B's that belong to A.id=x?
Edit:
After I load either A or B, I can easily get references to lists B and A respectively.
My real problem is making a single query that excludes all B's that are already associated with A.
This is what I want to do:
query.Where(**b.ID NOT IN (SELECT B.ID FROM AB WHERE A=5)** )
I'm sure I could do this with a raw sql query, but I want to be consistent and use IQueryable/LINQ where I can.

You can try this:
var bsNotAssociatedWithA5 = context.Bs
.Where(b => !b.As.Any(a => a.Id == 5))
.ToList();
It creates the following SQL:
SELECT
[Extent1].[BId] AS [BId],
[Extent1].[BColumn1] AS [BColumn1],
// more columns
FROM [dbo].[Bs] AS [Extent1]
WHERE NOT EXISTS
(SELECT 1 AS [C1]
FROM [dbo].[ABs] AS [Extent2]
WHERE ([Extent1].[BId] = [Extent2].[BId]) AND (5 = [Extent2].[AId]))
Edit
When using DbContext (EF >= 4.1) you can inspect the SQL by using ToString() of the IQueryable:
var bsNotAssociatedWithA5Query = context.Bs
.Where(b => !b.As.Any(a => a.Id == 5));
string sql = bsNotAssociatedWithA5Query.ToString();
var bsNotAssociatedWithA5 = bsNotAssociatedWithA5Query.ToList();

A.Bs
If you have an instance of A you should have a property in the A class to retrive all the B-s from A.

Related

Can i do an update from select with ExecuteUpdate in EF?

In EF7 there is a new ExecuteUpdate function to do updates on a table without retrieving the data from the server first.
Is it possible to do an update from select with this method in any way where it is using data from another table?
To be more concrete can i express this SQL in EF:
UPDATE
Table_A
SET
Table_A.col1 = Table_B.col1,
Table_A.col2 = Table_B.col2
FROM
Some_Table AS Table_A
INNER JOIN Other_Table AS Table_B
ON Table_A.id = Table_B.id
WHERE
Table_A.col3 = 'cool'
The following query updates table with values from joined table.
var query =
from a in context.TableA
join b in context.TableB on a.id equals b.id
where a.col3 == "cool"
select new { a, b };
query.ExecuteUpdate(s =>
s.SetProperty(x => x.a.col1, x => x.b.col1)
.SetProperty(x => x.a.col2, x => x.b.col2)
);

How to convert C# Linq to query in SQL Server?

I'm a junior developer and trying to convert the following linq statement to T-SQL:
var items = from u in DataContext.Users_SearchUsers(searchPara.UserFirstName,
searchPara.UserLastName,
searchPara.UserEmailAddress,
fetchOptions.page,
fetchOptions.rp,
fetchOptions.sortname,
fetchOptions.sortorder)
.ToList()
join a in DataContext.UserAccesses
.Where(x => x.Access.AccessTypeId == 4).ToList() on u.UserID equals a.UserId into accessGroup
select new {};
Can one please help me ? into accessGroup ---> (very important)
First of all you need to understand where your data is coming from. You are loading information from Users_SearchUsers on the one hand and UserAccesses on the other hand. The first query looks like
select <somecolumns>
from users
where <somefilters>;
(you need to use your actual columns and criteria, but Users_SearchUsers is not specified in the question at all). I have ignored paging here for the sake of simplicity
The second query looks like this:
select *
from user_accesses
where access_type_id = 4;
Let's join the two:
select <someoutercolumns>
from
(
select <someinnercolumns>
from users
where <somefilters>
) t1
join
(
select <someotherinnercolumns>
from user_accesses
where access_type_id = 4
) t2
on t1.user_id = t2.user_id;
These queries are probably not the exact solutions you need, but you want the answers to improve, then improve your question.
The requirement makes sense if the LINQ query is very slow. In that case you will need to refactor it in the following manner:
select <somecolumns>
from users
join user_accesses
on users.user_id = user_accesses.user_id and user_accesses.access_type_id = 4
where <somefilters>;
you can use this code
select *(you can put your columns instead *)
from Users
join UserAccesses
on Users.userid = UserAccesses.userid
where UserAccesses.typeid = 4;

How to get records from tables in custom order of ids?

I have some Ids store in below variable:
List<int> Ids;
Now I want to get records based on above Ids but with same order as it is in above Ids.
For eg: Records are like this in database:
Employee:
Id
1
2
3
4
5
Now if Ids array holds Ids like this : 4,2,5,3,1 then I am trying to get records in this order order only:
Query:
var data = context.Employee.Where(t => Ids.Contains(t.Id)).ToList();
But above query is giving me output like it is in table:
Id
1
2
3
4
5
Expected output :
Id
4
2
5
3
1
Update:I have already tried this below solution but as this is entity framework it didn't work out:
var data = context.Employee.Where(t => Ids.Contains(t.Id))
.OrderBy(d => Ids.IndexOf(d.Id)).ToList();
For above solution to make it working I have to add to list :
var data = context.Employee.Where(t => Ids.Contains(t.Id)).ToList()
.OrderBy(d => Ids.IndexOf(d.Id)).ToList();
But I don't want to load data in memory and then filter out my record.
Since the order in which the data is returned when you do not specify an ORDER BY is not determined, you have to add an ORDER BY to indicate how you want it sorted. Unfortunately you have to order based on objects/values in-memory, and cannot use that to order in your SQL query.
Therefore, the best you can do is to order in-memory once the data is retrieved from the database.
var data = context.Employee
// Add a criteria that we only want the known ids
.Where(t => Ids.Contains(t.Id))
// Anything after this is done in-memory instead of by the database
.AsEnumerable()
// Sort the results, in-memory
.OrderBy(d => Ids.IndexOf(d.Id))
// Materialize into a list
.ToList();
Without stored procedures you can use Union and ?: that are both canonical functions.
I can't immagine other ways.
?:
You can use it to assign a weigth to each id value then order by the weigth. Also, you have to generate ?: using dynamic linq.
What is the equivalent of "CASE WHEN THEN" (T-SQL) with Entity Framework?
Dynamically generate LINQ queries
Union
I think this is the more simple way to obtain it. In this case you can add a Where/Union for each Id.
EDIT 1
About using Union you can use code similar to this
IQueryable<Foo> query = context.Foos.AsQueryable();
List<int> Ids = new List<int>();
Ids.AddRange(new[] {3,2,1});
bool first = true;
foreach (int id in Ids)
{
if (first)
{
query = query.Where(_ => _.FooId == id);
first = false;
}
else
{
query = query.Union(context.Foos.Where(_ => _.FooId == id));
}
}
var results = query.ToList();
This generate the followiong query
SELECT
[Distinct2].[C1] AS [C1]
FROM ( SELECT DISTINCT
[UnionAll2].[C1] AS [C1]
FROM (SELECT
[Distinct1].[C1] AS [C1]
FROM ( SELECT DISTINCT
[UnionAll1].[FooId] AS [C1]
FROM (SELECT
[Extent1].[FooId] AS [FooId]
FROM [Foos] AS [Extent1]
WHERE [Extent1].[FooId] = #p__linq__0
UNION ALL
SELECT
[Extent2].[FooId] AS [FooId]
FROM [Foos] AS [Extent2]
WHERE [Extent2].[FooId] = #p__linq__1) AS [UnionAll1]
) AS [Distinct1]
UNION ALL
SELECT
[Extent3].[FooId] AS [FooId]
FROM [Foos] AS [Extent3]
WHERE [Extent3].[FooId] = #p__linq__2) AS [UnionAll2]
) AS [Distinct2]
p__linq__0 = 3
p__linq__1 = 2
p__linq__2 = 1
EDIT 2
I think the best approach is in memory approach because it has the same network load, EF does not generate the ugly query that could not work on databases different from SQL Server and code is more readable. In your particular application could be that union/where is better. So, generally I would suggest you to try memory approach then, if you have [performance] issues, you can check if union/where is better.

Entity Framework select most recent record for each type of record

I have a table called values that looks like this:
+-------+------------+-----------+----------+
|Id |DateTime |SensorId |Value |
+-------+------------+-----------+----------+
SensorId is a foreign key to a table of the sensor details. There will be 10m+ records in this values table.
I can run this sql command to return the most recent record for each SensorId and it runs in about 0.3 seconds.
SELECT a.*
FROM Values as a
INNER JOIN (
SELECT SensorId, MAX(ID) maxId
FROM Values
GROUP BY SensorId
) b ON a.SensorId = b.SensorId
AND a.Id = b.maxId
ORDER BY a.SensorId ASC
How can I achieve the same output with entity framework in a c# application while maintaining (or improving) the performance?
With LINQ to Entities and lambdas you can do it like this:
dataContext.Values.GroupBy(p => p.SensorId)
.Select(p => p.FirstOrDefault(w => w.Id == p.Max(m => m.Id)))
.OrderBy(p => p.SensorId).ToList()
where dataContext is your instance of ObjectContext class. ToList() compiles the query.
I guess it would not be possible reach better performance than pure SQl query because by using EF you are adding abstraction layer to the process.
EF is usually very slow with GroupBy command. I suggest try sql query in EF directly
(this code is for EF Core)
context.Values.FromSqlRaw<Values>("SELECT a.*
FROM Values as a
INNER JOIN (
SELECT SensorId, MAX(ID) maxId
FROM Values
GROUP BY SensorId
) b ON a.SensorId = b.SensorId
AND a.Id = b.maxId
ORDER BY a.SensorId ASC").ToList<Values>();
FromSqlRaw is faster than a normal Linq Query. for EF you can try context.ExecuteQuery<Values> by the same way.

Select category tree in Entity Framework

I have a Category table with a tree structure (Id,MasterId)
I'd like to select all products that belong to a Category and all Child Categories.
Today I use this SQL Query which works, but I'd like to add pagination and that would be easier with a pure LINQ query. I use Entity Framework 4.
#Count int = 100,
#CategoryId int
with mq as
(
select c.Id as parent, c.Id as child
from dbo.Categories c
where c.Id = #CategoryId
union all
select q.child, c.Id
from mq q
inner join dbo.Categories c on q.child = c.MasterId
)
select top (#Count) P.* from Products P
inner join ProductToCategory PC ON(PC.ProductId = P.Id)
where PC.CategoryId in (
select child from mq
)
and P.PublishStatus = 1
order by P.PublishedDate DESC;
Any ideas how to get a nice LINQ query on this with pagination (current page, number of products per page, total product count)?
This is recursive / hiearchical query with table expression. EF does not provide support for such queries. If you want to receive data by single roundtrip to DB you must wrap it in stored procedure and import that procedure to your entity framework model.
Paging in SQL is also possible when using table expressions and ROW_NUMBER().
there is an idea. i haven't tested it, so dont blame if it doesn't work :P
var ids = context.TreeItems.Where(x => x.Id == parentId).Select(x => (int?)x.Id);
var tmp = ids;
while (true)
{
IQueryable<int?> localIds = tmp;
var subIds = context.TreeItems.Where(x => ids.Contains(x.ParentId)).Select(x => (int?)x.Id);
if (subIds.Any())
{
tmp = subIds;
ids = ids.Union(subIds);
}
else
break;
}
var allSubItems = context.TreeItems.Where(x => ids.Contains(x.Id));

Categories

Resources