tags:

views:

164

answers:

3

I would love a solution to my current problem, but I would love EVEN MORE if I can understand what that error actually means.

I have LINQ to SQL classes for two tables in my DB: Providers and Assignments. I added the following member to the Provider class:

public IEnumerable<Assignment> Assignments 
    {
        get
        {
            return (new linqDataContext())
                .Assignments
                .Where(a => a.ProviderID == this.ProviderID);
        }
    }

Then, I bind a GridView using a query that pulls from the parent Provider and uses the child member Assignments, like this:

protected void PopulateProviders()
    {
        linqDataContext context = new linqDataContext();
        var list = from p in context.Providers
                   where (p.Assignments.Count(a => a.Category == ddlCategory.SelectedValue) > 0)
                   select p;

        lvProviders.DataSource = list;
        lvProviders.DataBind();
    }

At .DataBind(), when it actually runs the query, it throws the following error:

Member access 'System.String Category' of 'Namespace.Assignment' not legal on type 'System.Collections.Generic.IEnumerable`1[Namespace.Assignment].

I've tried checking for nulls (a => a != null && a.Category ...) but that hasn't worked. I'm not sure what to try next. I think that, if I knew what the error is trying to tell me, I could find the solution. As it stands, I don't know why member access would be illegal.

+3  A: 

That Assignments property is all wrong. First of all, property getters should not have side-effects, and more importantly, entity classes should never have reverse dependencies on the DataContext. Linq to SQL has no way to decipher this query; it's relying on a property that does all sorts of crazy stuff that Linq to SQL can't hope to understand.

Get rid of that Assignments property now. Instead of doing that, you need to write this query as a join:

int category = (int)ddlCategory.SelectedValue;
var providers =
    from p in context.Providers
    join a in context.Assignments
        on p.ProviderID equals a.ProviderID
        into g
    where g.Count(ga => ga.Category == category) > 0
    select p;

That should do what you're trying to do if I understood the intent of your code correctly.

One last side note: You never dispose properly of the DataContext in any of your methods. You should wrap it like so:

using (var context = new linqDataContext())
{
    // Get the data here
}
Aaronaught
Awesome. An extra point to you for "letting me have it". Thanks for helping me learn something important.
Byron Sommardahl
@Byron: Lol, apologies if it came off as a rant, it was my best attempt at an explanation of why L2S was choking - it saw the expression and went "OMG WTF" like I did. :P
Aaronaught
A: 

I think somewhere it doesn't know that type that is in the IEnumerable. You are trying to call a method that is not part of the IEnumerable inteface.

Why don't you just move the query from the property out to the PopulateProviders() method?

ctrlShiftBryan
A: 

Remove your custom-defined Assignments property. In the your Linq-To-SQL dbml file, create an association between Providers and Assignments, with Providers as the parent property, and ProviderID as the Participating Property for both entities. LINQ will generate a property "IEnumerable Assignments" based on matches between ProviderID using a consistent DataContext.

Jake