I'm trying to build my l2s query based on the existence of a parameter. I am able to achieve this for direct properties of my object, but when one of the properties is a many -> many entity, I'm unable to figure it out.
For example, my user table has a name column.
There is also a brand table and a user may have multiple brands as stored in the brand_users table.
I want to append to my query a condition that will query only users that have an entry in the brand_users table with a specific brandid.
GetUser(UserSearchParameter searchParam)
{
var query = from u in Users select u;
if(searchParam.Name != null)
query = query.Where(u => u.Name.Contains(searchParam.Status)); // this works!!
if(searchParam.BrandId != null)
query = query.Where??? // this is where I'm stuck
return new List<user>(query);
}
How about:
query = query.Where(u => Brands.Any(brand => brand.UserId == u.UserId &&
brand.BrandId == searchparam.brandId));
It's hard to give more detail without knowing the structure of your brands table though, or how it's represented in LINQ to SQL.
Something like
query = query.Where(u => u.Brand_Users.Any());
Assuming you've mapped the brand_users many->many table in a L2S relationship, with the name as above.
Related
I have written two queries which look like:
var loggedUser2 = ctx.Users.Where(y => y.Email == User.Identity.Name).Select(usr => new Users { UserId = usr.UserId }).AsEnumerable();
And second query looks like this:
var loggedUser = ctx.Users.FirstOrDefault(y => y.Email == User.Identity.Name);
The second query noticabely takes much more time to pull a single record from a table from a remote server as I can tell.
For the first query I'm getting an error:
The entity or complex type 'Users' cannot be constructed in a LINQ to Entities query.
when I try to access the property UserId of the "Users" object.
Now I have a couple of questions:
Why do I get this error and how do I actually access a property of a collection which is IEnumerable? I get it that I can materialize the query by using .ToList() and then have it accessed at [0].UserId, but I don't think this is the right way to do it?
What is the most efficient way to select a single column for a single records from a table (UserId in my case)? How would that query looks like (besides using a stored procedure).
Can someone help me out ? :)
you can declare a DTO or you can use an anonymous type like this:
var user = ctx.Users
.Where(u => u.Email == email)
.Select(u => new { UserId = u.UserId })
.FirstOrDefault()
I have a database that contains 3 tables:
Phones
PhoneListings
PhoneConditions
PhoneListings has a FK from the Phones table(PhoneID), and a FK from the Phone Conditions table(conditionID)
I am working on a function that adds a Phone Listing to the user's cart, and returns all of the necessary information for the user. The phone make and model are contained in the PHONES table, and the details about the Condition are contained in the PhoneConditions table.
Currently I am using 3 queries to obtain all the neccesary information. Is there a way to combine all of this into one query?
public ActionResult phoneAdd(int listingID, int qty)
{
ShoppingBasket myBasket = new ShoppingBasket();
string BasketID = myBasket.GetBasketID(this.HttpContext);
var PhoneListingQuery = (from x in myDB.phoneListings
where x.phonelistingID == listingID
select x).Single();
var PhoneCondition = myDB.phoneConditions
.Where(x => x.conditionID == PhoneListingQuery.phonelistingID).Single();
var PhoneDataQuery = (from ph in myDB.Phones
where ph.PhoneID == PhoneListingQuery.phonePageID
select ph).SingleOrDefault();
}
You could project the result into an anonymous class, or a Tuple, or even a custom shaped entity in a single line, however the overall database performance might not be any better:
var phoneObjects = myDB.phoneListings
.Where(pl => pl.phonelistingID == listingID)
.Select(pl => new
{
PhoneListingQuery = pl,
PhoneCondition = myDB.phoneConditions
.Single(pc => pc.conditionID == pl.phonelistingID),
PhoneDataQuery = myDB.Phones
.SingleOrDefault(ph => ph.PhoneID == pl.phonePageID)
})
.Single();
// Access phoneObjects.PhoneListingQuery / PhoneCondition / PhoneDataQuery as needed
There are also slightly more compact overloads of the LINQ Single and SingleOrDefault extensions which take a predicate as a parameter, which will help reduce the code slightly.
Edit
As an alternative to multiple retrievals from the ORM DbContext, or doing explicit manual Joins, if you set up navigation relationships between entities in your model via the navigable join keys (usually the Foreign Keys in the underlying tables), you can specify the depth of fetch with an eager load, using Include:
var phoneListingWithAssociations = myDB.phoneListings
.Include(pl => pl.PhoneConditions)
.Include(pl => pl.Phones)
.Single(pl => pl.phonelistingID == listingID);
Which will return the entity graph in phoneListingWithAssociations
(Assuming foreign keys PhoneListing.phonePageID => Phones.phoneId and
PhoneCondition.conditionID => PhoneListing.phonelistingID)
You should be able to pull it all in one query with join, I think.
But as pointed out you might not achieve alot of speed from this, as you are just picking the first match and then moving on, not really doing any inner comparisons.
If you know there exist atleast one data point in each table then you might aswell pull all at the same time. if not then waiting with the "sub queries" is nice as done by StuartLC.
var Phone = (from a in myDB.phoneListings
join b in myDB.phoneConditions on a.phonelistingID equals b.conditionID
join c in ph in myDB.Phones on a.phonePageID equals c.PhoneID
where
a.phonelistingID == listingID
select new {
Listing = a,
Condition = b,
Data = c
}).FirstOrDefault();
FirstOrDefault because single throws error if there exists more than one element.
I have a table with many fields and I want to get only a few individual fields, I work with EF and I add another table to the query as follows
var Test= ve.Folders.Include("Hosting")
.Where(a => a.Collateral!= true)
.AsEnumerable()
.Select(p => new
{
id = p.Folder_Id,
name = p.Full_Name,
add = p.Address,
date1 = p.Collateral_Date,
sName = p.Hosting._Name
})
.ToArray();
But with the field (sName= p.Hosting._Name) that is associated with the second table without any value query not working
Many attempts have been tried but without result (interesting when I ask without Select everything works well)
Thanks in advance for any help
One thing to note is that, in this case, there's little benefit to the Select after the call to AsEnumerable, since all the data in the table is still queried from the database (not just the fields you specifiy).
If you want to avoid that, and only query those five fields, you can remove the AsEnumerable call. That means the Select will execute as part of the SQL query. This also means the Include is unnecessary, since the Select will query all of the data you want.
var Test= ve.Folders
.Where(a => a.Collateral!= true)
.Select(p => new
{
id = p.Folder_Id,
name = p.Full_Name,
add = p.Address,
date1 = p.Collateral_Date,
sName = p.Hosting._Name
})
.ToArray();
I have a Linq to NHibernate query as follows:
var profile =
from UserProfile up in _Session.Query<UserProfile>()
.Fetch(x=>x.Messages)
where up.UserName == userName
select up.Messages;
this returns an IQueryable<IList<UserMessage>> which I then have to run a SelectMany() on. I'd prefer if I could just return an IQueryable<UserMessage> object instead, especially as the query will never return more than one user profile. Can this be done, or am I stuck with the extra step?
If you map the other side of the navigation e.g have a UserProfile property on the UserMessage class, your can start from UserMessage:
var messages =
from UserMessage um in _Session.Query<UserMessage>()
where um.UserProfile.UserName == userName
select um;
Otherwise you need to use SelectMany() to get a flattened out list.
Could you query the messages table directly and use the reverse association?
IQueryable<Message> messages = ...;
var filtered = from m in messages
where m.UserProfile.UserName == userName
select m;
Also, if you're willing to forgo query syntax you could make this shorter with:
var profile = _Session.Query<UserProfile>()
.Where(up => up.UserName == userName)
.SelectMany(up => up.Messages);
I would like to get the list of albums (Distinct) which was sung by the artistId=1
I am very new to LINQ to SQL and do not know how to join multiple tables. Please see the database diagram below:
alt text http://a.imageshack.us/img155/8572/13690801.jpg
SingBy is the middle table between Track and Artist.
How could I achieve this?
var albums = from singer in artist
from sb in singby
from t in track
from a in album
where singer.artistId == 1 &&
sb.artistId == 1 &&
sb.trackId == t.trackId &&
a.albumId == track.albumId
select a;
I'm sure there must be a better way. You should look into creating Navigation Properties on your entities. Navigation Properties are like foreign keys.
Edit - corrected to get albums, not artists.
Now, I wrote the codes like the following and it works.
var albums = (from a in db.artists
where a.artistId == 1
join sb in db.singbies on a equals sb.artist
join t in db.tracks on sb.track equals t
join al in db.albums on t.album equals al
select al).Distinct();
return albums.ToList() as List<album>;
I tested the Chad's version and it works too. I would like to know which way is better and good for query optimization? Thanks all.
If you have all the foreign key relationship defined, you should be able to issue call like below:
dc.GetTable<Album>().Where(a => a.Track.Singby.ArtistId == 1).ToList();
This is relying on Linq to perform lazy load for Track and Singby automatically when required. Obviously this is not optimal to use when you have a large set of data in the db and performance is critical. You can chain the query with GroupBy or Distinct operation to return only the distinct set such as
dc.GetTable<Album>().Where(a => a.Track.Singby.ArtistId == 1).Distinct().ToList();
I would like to get the list of albums
(Distinct) which was sung by the
artistId=1
DBDataContext = new DBDataContext();
album[] = db.artists.Where(a => a.artistId == 1) /* Your artist */
.SelectMany(a => a.singbies) /* Check if `singby` converted to `singbies` */
.Select(sb => sb.track) /* The tracks */
.Select(t => t.album) /* The albums */
.GroupBy(al => al.albumId) /* Group by id */ /* "Distinct" for objects */
.Select(alG => alG.First()) /* Select first of each group */
.ToArray();
IEnumerable<Album> query =
from album in myDC.Albums
let artists =
from track in album.Tracks
from singBy in track.SingBys
select singBy.Artist
where artists.Any(artist => artist.ArtistId == 1)
select album;
List<int> Ids = dc.Albums.Where(a => a.Track.Singby.ArtistId == 1).Select(a=> a.albumId).Distinct().ToList();
List<Album> distinctAlbums = dc.Albums.Where(a => distinctAlbumIds.Contains(a.albumId)).ToList();
Hey TTCG, above is the simplest way to do it. This is because doing a Distinct on a List of objects won't do it based on the albumId.
Either you do it in two steps as above, or, you write your own Album Comparer which specifies uniqueness based on AlbumId and pass it to the Distinct call on a List.
NOTE:
The above will only work if you've defined the constraints in your DBML, but better still in your DB.
For best practices, always define your relationships IN THE DATABASE when using Linq to SQL, as Linq to SQL is not like EF, or NHibernate, in that is does not "abstract" your db, it simply reflects it. It's a tool for Data Driven Design, not Domain Driven, so define the relationships in the db.