Linq query join table - linq

I have a User table and a group table one user can be part of many groups
[USERID]----*-[USERID GROUPID]-*-----[GROUPID]
(join table)
public partial class user
{
public int user_id { get; set; }
public string name { get; set; }
public virtual ICollection<group> groups{ get; set; }
}
public partial class group
{
public int user_id { get; set; }
public string name { get; set; }
public virtual ICollection<user> users{ get; set; }
}
1) I need to return all the users that belongs to a specific group
var queryable = (from g in db.groups
where g.group_id == id
select g.users)
.ToList()
.Select(u => new {
id = u.id, //Error does not contain definition for id
name = u.name //Error does not contain definition for name
});
2) I need to return a specific user that belongs to a specific group
Thanks for your suggestions

I need to return all the users that belongs to a specific group
Lambda syntax:
db.groups.Where(g => g.group_id == id).SelectMany(g => g.users)
Or query syntax:
from g in db.groups
where g.group_id == id
from u in g.users
select u
I need to return a specific user that belongs to a specific group
Just like query above, with one additional filter
db.groups.Where(g => g.group_id == id)
.SelectMany(g => g.users)
.Where(u => u.id == userId)
Query syntax:
from g in db.groups
where g.group_id == id
from u in g.users
where u.id == userId
select u

Try something like this:
var queryable = (from p in db.plants
join u in db.users on p.userId equals u.id
where p.plant_id == plant_id
select u)
.ToList()
.Select(u => new {
id = u.id,
name = u.name
});
where p.userId is the column which connect plants and users tables

var queryable = (from p in db.plants
join u in db.users on p.userId equals u.id
where p.plant_id == plant_id
select new { p.id, p.name, u.name}).ToList();

Related

Joining multiple tables to return a list using LINQ

I have a LINQ statement I am trying to figure out - I am relatively new to this so please excuse my ignorance. I want to return a person list, each person having a list of interests.
The person(p) table joins to the personinterest(pi) table by p.id = pi.personid
The personinterest table joins to the interest(i) table, pi.interestid to i.id.
public class Persons
{
public int Id { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
...
public IList<Interest> PersonInterests { get; set; }
}
public class Interest
{
public string InterestName { get; set; }
}
The class I am returning is a person, each with its PersonInterests list populated with 0 to many interests. The Linq statement I have below is returning data, but each person record is only getting one interest, and persons with more than one interest are having their person data duplicated as shown below the linq statement
var interests = _db.Interests;
return (from p in _db.People
join i in _db.PersonInterests on p.Id equals i.PersonId
join s in _db.Interests on i.InterestId equals s.Id
select new Persons{
Id = p.Id,
FirstName = p.FirstName,
LastName = p.LastName,
Age = p.Age,
Address = p.Address,
City = p.City,
StateAbbrev = p.StateAbbrev,
ZipCode = p.ZipCode,
PersonInterests = (from r in interests where r.Id == i.InterestId select r).ToList()
}).ToList();
Results:
{"id":1,"lastName":"Alexander","firstName":"Carson","age":23,"address":"123 4th Street","city":"Jamestown","stateAbbrev":"NV","zipCode":"65465","personInterests":[{"id":1,"interestName":"Basketball"}],"photo":null}
{"id":1,"lastName":"Alexander","firstName":"Carson","age":23,"address":"123 4th Street","city":"Jamestown","stateAbbrev":"NV","zipCode":"65465","personInterests":[{"id":2,"interestName":"Camping"}],"photo":null},
Instead of this, I would like the data to look like this:
{"id":1,"lastName":"Alexander","firstName":"Carson","age":23,"address":"123 4th Street","city":"Jamestown","stateAbbrev":"NV","zipCode":"65465","personInterests":[{"id":1,"interestName":"Basketball"}, {"id":2,"interestName":"Camping"}],"photo":null}
I have struggled with this for a while, any help is greatly appreciated.
So, after staring at this for hours I realized it was stupid to try and do this in one query. I split it up and got it working. First retrieved the person data, then for each person, built their list if interests.
public async Task<IEnumerable<PersonResource>> GetPeople()
{
IEnumerable<PersonResource> people = await (from p in _db.People
select new PersonResource
{
Id = p.Id,
FirstName = p.FirstName,
LastName = p.LastName,
Age = p.Age,
Address = p.Address,
City = p.City,
StateAbbrev = p.StateAbbrev,
ZipCode = p.ZipCode,
Photo = p.Photo,
Interests = new List<string>()
}).ToListAsync();
foreach (PersonResource person in people)
{
person.Interests = (from iint in _db.Interests
join n in _db.PersonInterests on iint.Id equals n.InterestId
where n.PersonId == person.Id
select iint.InterestName).ToList();
}
return people;
// return Mapper.Map<List<Person>, List<PersonResource>>(people);
}
do it like this
(from p in _db.People
select new {
Id = p.Id,
FirstName = p.FirstName,
LastName = p.LastName,
Age = p.Age,
Address = p.Address,
City = p.City,
StateAbbrev = p.StateAbbrev,
ZipCode = p.ZipCode,
Photo = p.Photo,
Interests = (from i in _db.Interests
where i.PersonId == p.Id
select i.InterestName).ToList()
}).ToList();

Left Join using LAMBDA to get Result in API

How to implement this Join which is in the code below into C# using LAMBDA
Select
VD.Id
, VD.BusinessAddress
, VD.BusinessDesc
, VD.BusinessEmail
, VD.BusinessName
, VD.BusinessZip
, VD.ContactPerson
, VD.ContactNo
, VD.ProfileUrl
, L.Name
, BC.BusinessCategory
from vendorDomain VD WITH(NOLOCK)
left Join Location L WITH(NOLOCK) ON VD.City = L.Id
left join Business_Category BC WITH(NOLOCK) ON VD.BusinessCategory = BC.BusinessId
where VD.IsDeleted = 0
I have to implement the join operation in the following API:
[HttpGet]
public async Task<IActionResult> Get()
{
var VendorList =await _vendorRepository.Query().Where(x => x.IsDeleted == false).ToListAsync();
return Ok(VendorList);
}
There are alot of examples out there but are way to confusing for a novice developer..
EDIT:
This is what I have tried as of now:
var employees = from vndr in context.vendorDomain
join C in context.Location on vndr.City equals C.Id into dep
from dept in dep.DefaultIfEmpty()
select new
{
vndr.BusinessAddress,
vndr.BusinessDesc,
vndr.BusinessEmail,
vndr.BusinessName,
vndr.BusinessWebsite,
vndr.BusinessZip,
vndr.ContactNo,
vndr.ContactPerson,
vndr.Created_At,
vndr.ProfileUrl,
vndr.Url,
dept.Name
};
We will do things first: do the joins and create a view model class that you will return. Because returning anonymous object and using dynamic does get messy.
ViewModel for the joined entities:
public class EmployeesViewModel
{
public string BusinessAddress { get; set; }
public string BusinessDesc { get; set; }
public string BusinessEmail { get; set; }
/* ....all remaining properties */
}
Then we join them properly and select them as an EmployeeViewModel:
var employees = from vndr in context.vendorDomain
join loc in context.Location on vndr.City equals loc.Id
join bus in context.Business_Category on vndr.BusinessCategory = bus.BusinessId
select new EmployeeViewModel
{
BusinessAddress = vndr.BusinessAddress,
BusinessDesc = vndr.BusinessDesc,
BusinessEmail = vndr.BusinessEmail,
/* ... remaining properties here*/
};
Or, if you want the method syntax:
var employees = context.vendorDomain
.Join(context.Location,
vndr => vndr.City,
loc => loc.Id,
(vndr, loc) => new { vndr, loc,})
.Join(context.Business_Category,
vndr_loc.vndr.BusinessCategory,
bus.BusinessId,
(vndr_loc, bus) => new {vndr_loc.vndr, vndr_loc.loc, bus})
.Select(x => new EmployeeViewModel{
BusinessAddress = vndr.BusinessAddress,
BusinessDesc = vndr.BusinessDesc,
BusinessEmail = vndr.BusinessEmail,
/* ... remaining properties here*/
});
As per your comment, you need to print the vendorList after the join. Now that is pretty vague, but I assume you want to submit both to your client / view, so again, we create a ViewModel class for it:
public class EmployeeVendorListViewModel
{
public VendorList VendorList { get; set; }
public EmployeeViewModel Employees { get; set; }
}
The last thing we do is glue it all together in your ActionMethod and return it:
[HttpGet]
public async Task<IActionResult> Get()
{
//renamed using a lower case "v"
var vendorList = await _vendorRepository.Query()
.Where(x => x.IsDeleted == false)
.ToListAsync();
//the join from earlier. You should put it in a repo somewhere, so it does not clutter your controller
var employees = from vndr in context.vendorDomain
join loc in context.Location on vndr.City equals loc.Id
join bus in context.Business_Category on vndr.BusinessCategory = bus.BusinessId
select new EmployeeViewModel
{
BusinessAddress = vndr.BusinessAddress,
BusinessDesc = vndr.BusinessDesc,
BusinessEmail = vndr.BusinessEmail,
/* ... remaining properties here*/
};
//create the final view model and return it
var vm = new EmployeeVendorListViewModel
{
VendorList = vendorList,
Employees = employees
}
return Ok(vm);
}
If you want to use NOLOCK in your query, you have to wrap it in a TransactionScope. This has already been answered here on StackOverflow: NOLOCK with Linq to SQL

LINQ with Group, Join and Where Easy in SQL not in LINQ?

I have trouble understand how to translate SQL into LINQ. I would like to do the following but can't figure out how to get the Group By to work
var query = from s in Supplier
join o in Offers on s.Supp_ID equals o.Supp_ID
join p in Product on o.Prod_ID equals p.Prod_ID
where s.City == "Chicago"
group s by s.City into Results
select new { Name = Results.Name };
I just need to do something simple like display the product name of this simple query, how does the group by work with joins and a where?
You haven't provided classes so I assumed that they are like below:
public class Supplier
{
public int SupplierID { get; set; }
public string SuppierName { get; set; }
public string City { get; set; }
}
public class Product
{
public int ProductID { get; set; }
public string ProductName { get; set; }
}
public class Offer
{
public int SupplierID { get; set; }
public int ProductID { get; set; }
}
Then I added data for testing:
List<Supplier> supplierList = new List<Supplier>()
{
new Supplier() { SupplierID = 1, SuppierName = "FirstCompany", City = "Chicago"},
new Supplier() { SupplierID = 2, SuppierName = "SecondCompany", City = "Chicago"},
new Supplier() { SupplierID = 3, SuppierName = "ThirdCompany", City = "Chicago"},
};
List<Product> productList = new List<Product>()
{
new Product() { ProductID = 1, ProductName = "FirstProduct" },
new Product() { ProductID = 2, ProductName = "SecondProduct" },
new Product() { ProductID = 3, ProductName = "ThirdProduct" }
};
List<Offer> offerList = new List<Offer>()
{
new Offer() { SupplierID = 1, ProductID = 2},
new Offer() { SupplierID = 2, ProductID = 1},
new Offer() { SupplierID = 2, ProductID = 3}
};
If you want to show names of suppliers whiches products have been offered then your LINQ query should be as this:
IEnumerable<string> result = from supplier in supplierList
join offer in offerList on supplier.SupplierID equals offer.SupplierID
join product in productList on offer.ProductID equals product.ProductID
where supplier.City == "Chicago"
group supplier by supplier.SuppierName into g
select g.Key;
You can see if correct names have been selected:
foreach (string supplierName in result)
{
Console.WriteLine(supplierName);
}
It must give following result:
FirstCompany
SecondCompany
You could try this:
var query = from s in Supplier
join o in Offers on s.Supp_ID equals o.Supp_ID
join p in Product on o.Prod_ID equals p.Prod_ID
where s.City == "Chicago"
group s
by new {s.City, s.Name} //added this
into Results
select new { Name = Results.Key.Name };
You group s (Supplier) by s.City. The result of this is an IGrouping<City, Supplier>. I.e. only City and Supplier are within reach after the grouping: for each City you get an IEnumerable<Supplier> of its suppliers (which will be multiplied by the joins, by the way).
Since you also have the condition where s.City == "Chicago" grouping by city is of no use. There is only one city. So I think you may as well do something like this:
from s in Supplier
join o in Offers on s.Supp_ID equals o.Supp_ID
join p in Product on o.Prod_ID equals p.Prod_ID
where s.City == "Chicago"
select new {
City = s.City.Name,
Supplier = s.Name,
Product = p.Name,
...
};

select all related objects

I have a linq query where I'm trying to return all MlaArticles that are related to all other WebObjects but I'm getting the error: The specified type member 'RelatedWebObjectIds' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.
Here's the Model...
public abstract class WebObject : IValidatableObject
{
public WebObject()
{
this.Id = Guid.NewGuid();
RelatedTags = new List<Tag>();
RelatedWebObjects = new List<WebObject>();
}
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid Id { get; set; }
public virtual ICollection<WebObject> RelatedWebObjects { get; set; }
public IList<Guid> RelatedWebObjectIds { get; set; }
}
Thanks for your help...
List<MlaArticle> assignedWebObjects = (from e in db.MlaArticles
where
(from w in db.WebObjects
from r in w.RelatedWebObjectIds
where w.Id == id
select r).Contains(e.Id)
select e).OrderBy(x => x.Title).ToList();
New query. Produces different error: WebObject does not contain a definition for 'Contains' and the best extension method overload ... has some invalid arguments.
List<MlaArticle> assignedWebObjects = (from e in db.MlaArticles
where
(from w in db.WebObjects
from r in w.RelatedWebObjects
where w.Id == id
select r.RelatedWebObjectIds).Contains(e.Id)
select e).OrderBy(x => x.Title).ToList();
Is there a RelatedWebObjects navigation property in your MlaArticle entity? If there is, you can do that instead:
List<MlaArticle> assignedWebObjects = (from e in db.MlaArticles
where
(from w in db.WebObjects
from r in w.RelatedWebObjects
where w.Id == id
select r.Id).Contains(e.Id)
select e).OrderBy(x => x.Title).ToList();
List<MlaArticle> assignedWebObjects = (from e in db.MlaArticles
where
(from w in db.WebObjects
from r in w.RelatedWebObjects
where w.Id == id
select r.RelatedWebObjectIds).Any(i => i == e.Id)
select e).OrderBy(x => x.Title).ToList();

LINQ to SQL MAX in WHERE clause

I am new to Linq so as expected I have encountered difficulties.
What I am trying to achieve is this:
SELECT id, name, password
FROM users u
WHERE u.id = (SELECT MAX(u1.id) FROM users u1);
My Linq is:
var dbUsers = from u in context.Users
where u.Id == (context.Users.Max(u1 => u1.Id))
select u;
But I always end with the following exception:
Unable to create a constant value of type 'Bla.Users'. Only primitive
types ('such as Int32, String, and Guid') are supported in this
context.
Here is the users class:
public class Users
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Password { get; set; }
}
}
Here is my context class:
public class EFDbContext : DbContext
{
public DbSet<User> Users{ get; set; }
}
You need to select the ID property
var dbUsers = from u in context.Users
where u.Id == (context.Users.Select(u1 => u1.Id).Max())
select u;
I usually do my LINQing in lambda format...
var dbUsers = DataContext.Users
.Where(u => u.Id == (DataContext.Users.Max(u1 => u1.Id)))
.Select(u => new
{
Id = u.Id,
Name = u.Name,
Password = u.Password
});
If you want the comprehension format...
var dbUsers = from u in DataContext.Users
where u.Id == (DataContext.Users.Max(u1 => u1.Id))
select new
{
Id = u.Id,
Name = u.Name,
Password = u.Password
};
Consider using a let statement:
var dbUsers = from u in context.Users
let int maxId = context.Users.Max(u1 => u1.Id)
where u.Id == maxId
select u;
Please let me know if this one solves your problem:
var dbUser = (from u in context.Users
orderby u.Id descending).FirstOrDefault()
You could use lambda expressions:
var dbUser = context.Users.First(u => u.Id== (context.Users.Select(u2
=> u2.Id).Max()));
or:
var dbUser = context.Users.OrderByDescending(u => u.Id).FirstOrDefault();

Resources