views:

1312

answers:

4

Hi,

I am at a loss with the following query, which is peanuts in plain T-SQL.

We have three physical tables:

  • Band (PK=BandId)
  • MusicStyle (PK=MuicStyleId)
  • BandMusicStyle (PK=BandId+MusicStyleId, FK=BandId, MusicStyleId)

Now what I'm trying to do is get a list of MusicStyles that are linked to a Band which contains a certain searchstring in it's name. The bandname should be in the result aswell.

The T-SQL would be something like this:

SELECT b.Name, m.ID, m.Name, m.Description
FROM Band b 
INNER JOIN BandMusicStyle bm on b.BandId = bm.BandId
INNER JOIN MusicStyle m on bm.MusicStyleId = m.MusicStyleId
WHERE b.Name like '%@searchstring%'

How would I write this in Linq To Entities?

PS: StackOverflow does not allow a search on the string 'many to many' for some bizar reason...

+1  A: 

In Linq, actually you don't need to write anything, if you define the relation in the diagram in SQL database, and generated using the utility, the object hierarchy is built automatically. That means, if you do:

var bands = from ms in db.MusicStyle
            let b = ms.Bands
            where b.Name.Contains(SEARCHSTRING)
            select new {
                b.Name, ms.Name, 
                ms.ID, ms.Description};

If you look into the generated classes of entities, the BandMusicStyle should not appear as LINQ to Entities consider that Band and MusicStyle are many to many and that table is not necessary.

See if it works?

xandy
The BandMusicStyle table doesn't appear in my datamodel. I just want to have a list of musicstyles that are bound to a Band with the searchstring in it's name. How would you get a list of objects out of your query with Bandname, MusicStyleId, MusicStyleName and MusicStyleDescription? I don't want to have to iterate through this list and form it manually afterwards...
Peter
BandMusicStyle table WOULD NOT appear in entity model. This is purposely done by LINQ to Entities, coz it consider that intermediate table is just a "many-many join" so that it will not be generated, not like Linq 2 SQl. If you need those fields ONLY, you can select those in your select statement: select new {b.Name, b.MusicStyle.Name, b.MusicStyle.ID, b.MusicStyle.Description};
xandy
Yes I know that it would not appear... The problem you have in your current query is that b.Musicstyle is a collection of MusicStyles, since one Band can have multiple MusicStyles.
Peter
oh yes.. i did forgot that. I will edit it now
xandy
A: 
from ms in Context.MusicStyles
where ms.Bands.Any(b => b.Name.Contains(search))
select ms;

This just returns the style, which is what your question asks for. Your sample SQL, on the other hand, returns the style and the bands. For that, I'd do:

from b in Context.Bands
where b.Name.Contains(search)
group b by band.MusicStyle into g
select new {
    Style = g.Key,
    Bands = g
}

from b in Context.Bands
where b.Name.Contains(search)
select new {
    BandName = b.Name,
    MusicStyleId = b.MusicStyle.Id,
    MusicStyleName = b.MusicStyle.Name,
    // etc.
}
Craig Stuntz
isn't it possible to just return a list of new objects which contain the items I have written in my SQL statement??
Peter
Sure. Don't group, and return an anonymous type. I'll add an example.
Craig Stuntz
A: 

You could do the above, but that will bring back all your results once you start to iterate over them and the filtering is done in-memory rather than on the db.

I think what you're looking for is just a few joins?

var q = from b in db.Bands
join bm in db.BandMusicStyle on on b.BandId equals bm.BandId
join ms in db.MusicStyle on bm.MusicStyleId equals m.MusicStyleId
where b.Name.Contains(searchString)
select new { b.Name, ms.ID, ms.Name, ms.Description };

or something to this effect anyway

Ciaran
The problem is that Linq To Entities does not give you properties for the foreign keys in your table. Also, a linktable such as BandMusicStyle does not exist as it is only there to link a Band and a MusicStyle to eachother.
Peter
Ah, am still in Linq to Sql mode
Ciaran
Hey at least you solved the problem correctly, too bad it's not using the technology I need...
Peter
This might help a bit?http://weblogs.asp.net/zeeshanhirani/archive/2008/08/21/many-to-many-mappings-in-entity-framework.aspx
Ciaran
+2  A: 

This proved to be much simpler than it seemed. I've solved the problem using the following blogpost: http://weblogs.asp.net/salimfayad/archive/2008/07/09/linq-to-entities-join-queries.aspx

The key to this solution is to apply the filter of the bandname on a subset of Bands of the musicstyle collection.

var result=(from m in _entities.MusicStyle 
            from b in m.Band
            where b.Name.Contains(search)
            select new {
                BandName = b.Name,
                m.ID,
                m.Name,
                m.Description
            });

notice the line

from b IN m.Band

This makes sure you are only filtering on bands that have a musicstyle.

Thanks for your answers but none of them actually solved my problem.

Peter