Short query for this long one - c#

Can anybody please tell me shortest query for this :
var guestpartyids = db.CeremonyGuestParties.Where(p => p.CeremonyId == id)
.Select(p => p.GuestPartyId);
List<GuestParty> guestparties = new List<GuestParty>();
foreach (var party in guestpartyids)
{
guestparties.Add(db.GuestParties.Single(p => p.Id == party));
}

This should do it.
guestparties.AddRange(
from cgp in db.CeremonyGuestParties
where cgp.CeremonyId == id
join gp in db.GuestParties on cgp.GuestPartyId equals gp.Id
select gp
);
Please note that this will result in one database call, as where your code will result in 1+N queries. But it will not ensure there's only one matching ID, like Single() would do. This should be enforced on the database anyway, and not in code.

How about:
List<GuestParty> guestparties = from cgp in db.CeremonyGuestParties.
Where cgp.CeremonyId .id == id)
select cgp.Guestparties.ToList();

Related

Linq to Sql - How to get data from second level table

I'm newbie to linq to sql, just trying to understand what type of queries I can handle with linq.
Here is my database scheme,
I want to get all customers of a specific user and this is what I've done,
var userId = 4;
var companies = from c in db.Company
where c.UserId == userId
select c.Id;
var costumers = from c in db.Customers
where companies.Contains(c.CompanyId)
select c;
I'm just wondering whether it's a nice approach and is there any better method to handle this type of queries?
Use can also get customers by this way also:
var result = db.Customers.Join(
db.Company, customer => customer.CompanyId, comp => comp.Id, (customer, comp)
=> new { customer, comp }).Where(#t => #t.comp.UserId == 4)
.Select(#t => #t.customer);
You can also keep it simple like this.
select * from db.Customers Cus
inner join db.company Com on Com.Id = Cus.CompanyId
where Com.UserId= userId
Contains is the equivalent of IN in SQL and your Linq statement will be translated to a SQL statement. So I can't really see another way that will give you better performance with Linq. If you want to use less code you can maybe try the following instead:
var companies = db.Companies.Where(x=> x.UserId == userid).Select(x=>x.Id);
var customers = db.Customers.Where(x=> companies.Contains(x.CompanyId));

LINQ: Problem using DB with relations

I don't know how can I return posts to my view where their tags are equal to those who are passed to controller action.
I think there is some clever and easy way of doing this but I am very new to LINQ and SQL.
Code
// id = tag name, not it's id
public ActionResult Tag(string id)
{
// I get all the PostTags where PostTags.Tag.Name = id
var postTags = _db.PostTags.Where(x => x.Tag.Name == id);
// And what I do now?
}
Using joins in relational data is easier to grasp as a novice using query syntax instead of extension methods. The following is possible with extension methods (like .Join(...), etc), but this is closer to the SQL you might already be used to.
var postTags = from t in _db.Tags
join pt in _db.PostTags on t.ID equals pt.TagID
join p in _db.Posts on pt.PostID equals p.ID
where t.Name == id
select p;
Well to select them you could do something similar to..
var posts = _db.Posts.Where(post => post.PostTags.Any(postTag => postTag.Tag.Name == id));
This will just select all Posts where any of the related PostTags has a Tag with the name passed.

Crazy Query need some feedback

var query =context.Categories.Include("ChildHierarchy")
.Where(c =>
context.CategoryHierarchy.Where(ch => ch.ParentCategoryID == ch.ParentCategoryID)
.Select(ch => ch.ChildCategoryID).Contains(c.CategoryID));
Questions:
I need to include some data from another Navigation Propery (".Include("otherprop")")
Is it possible to do a select new after all of this?
Thanks
The title to your question intrigued me with the words "Crazy Query", and yes, you're right, it is a bit crazy.
You have a .Where(...) clause with the following predicate:
ch => ch.ParentCategoryID == ch.ParentCategoryID
Now that's going to always be true. So I guess that you're trying to do something else. I'll have a crack at what that might be at the end of my answer.
I then did some cleaning up of your query to get a better idea of what you're doing. This is what it now looks like:
var query =
context
.Categories
.Where(c => context
.CategoryHierarchy
.Select(ch => ch.ChildCategoryID)
.Contains(c.CategoryID));
So rather than use nested queries I would suggest something like this might be better in terms of readability and possibly performance:
var query =
from c in context.Categories
join h in context.CategoryHierarchy
on c.CategoryID equals h.ChildCategoryID into ghs
where ghs.Any()
select c;
This gives the same results as your query so hopefully this is helpful.
I do get the impression that you're trying to do a query where you want to return each Category along with any child categories it may have. If that's the case here are the queries you need:
var lookup =
(from c in context.Categories
join h in context.CategoryHierarchy
on c.CategoryID equals h.ChildCategoryID
select new { ParentCategoryID = h.ParentCategoryID, Category = c, }
).ToLookup(x => x.ParentCategoryID, x => x.Category);
var query =
from c in context.Categories
select new { Category = c, Children = lookup[c.CategoryID], };
The lookup query first makes a join on categories and the category hierarchies to return all children categories and their associated ParentCategoryID and then it creates a lookup from ParentCategoryID to a list of associated Category children.
The query now just has to select all categories and perform a lookup on the CategoryID to get the children.
The advantage of using the .ToLookup(...) approach is that it easily allows you to include categories that don't have children. Unlike using a Dictionary<,> the lookup does not throw an exception when you use a key that it hasn't got a value for - instead it returns an empty list.
Now, you can add back in the .Include(...) calls too.
var lookup =
(from c in context.Categories
.Include("ChildHierarchy")
.Include("otherprop")
join h in context.CategoryHierarchy
on c.CategoryID equals h.ChildCategoryID
select new { ParentCategoryID = h.ParentCategoryID, Category = c, }
).ToLookup(x => x.ParentCategoryID, x => x.Category);
var query =
from c in context.Categories
.Include("ChildHierarchy")
.Include("otherprop")
select new { Category = c, Children = lookup[c.CategoryID], };
Is that what you're after?
1) Then add it - context.Categories.Include("ChildHierarchy").Include("OtherCollection");
2) Absolutely, yes
var query = context.Categories
.Include("ChildHierarchy")
.Include("OtherProp")
.Where(c => context.CategoryHierarchy.Where(ch => ch.ParentCategoryID == ch.ParentCategoryID)
.Select(ch => ch.ChildCategoryID).Contains(c.CategoryID))
.Select(c => new { c.A, c.B, c.etc });

How to cast a Linq Dynamic Query result as a custom class?

Normally, I do this:
var a = from p in db.Products
where p.ProductType == "Tee Shirt"
group p by p.ProductColor into g
select new Category {
PropertyType = g.Key,
Count = g.Count() }
But I have code like this:
var a = Products
.Where("ProductType == #0", "Tee Shirt")
.GroupBy("ProductColor", "it")
.Select("new ( Key, it.Count() as int )");
What syntax could I alter to produce identical results, i.e., how do I do a projection of Category from the second Linq statement?
I know in both that g and it are the same and represent the entire table record, and that I am pulling the entire record in just to do a count. I need to fix that too. Edit: Marcelo Cantos pointed out that Linq is smart enough to not pull unnecessary data. Thanks!
Why would you have to do it at all? Since you still have all of the information after the GroupBy call, you can easily do this:
var a = Products
.Where("ProductType == #0", "Tee Shirt")
.GroupBy("ProductColor", "it")
.Select(c => new Category {
PropertyType = g.Key, Count = g.Count()
});
The type of Products should still flow through and be accessible and the regular groupings/filtering shouldn't mutate the type that is flowing through the extension methods.

Any Way to Use a Join in a Lambda Where() on a Table<>?

I'm in my first couple of days using Linq in C#, and I'm curious to know if there is a more concise way of writing the following.
MyEntities db = new MyEntities(ConnString);
var q = from a in db.TableA
join b in db.TableB
on a.SomeFieldID equals b.SomeFieldID
where (a.UserID == CurrentUser &&
b.MyField == Convert.ToInt32(MyDropDownList.SelectedValue))
select new { a, b };
if(q.Any())
{
//snip
}
I know that if I were to want to check the existence of a value in the field of a single table, I could just use the following:
if(db.TableA.Where(u => u.UserID == CurrentUser).Any())
{
//snip
}
But I'm curious to know if there is a way to do the lambda technique, but where it would satisfy the first technique's conditions across those two tables.
Sorry for any mistakes or clarity, I'll edit as necessary. Thanks in advance.
Yes, you can do this with extension methods. Note that you might get a more concise query by filtering each table first, though I suspect SQL Server would optimize it that way anyway.
if (db.TableA.Where( a => a.UserID == CurrentUser )
.Join( db.TableB.Where( b => b.MyField == Convert.ToInt32(MyDDL.SelectedValue) ),
o => o.someFieldID,
i => i.someFieldID,
(o,i) => o )
.Any()) {
...
}

Categories

Resources