views:

379

answers:

2

I am working on an employee-scheduling system. I think I have the database setup pretty well, and have run into a snag on pulling the data for my database and getting it onto the page. I am using LINQ to make things easy on myself.

Here is the Object Relational Map.

Here is my Linq select statement:

protected void LinqSelecting(object sender, LinqDataSourceSelectEventArgs e) {
    MilhouseDataClassesDataContext mdb = new MilhouseDataClassesDataContext();
    e.Result = from x in mdb.MilhouseHours
               group x by x.HourString into hour
               select new {
                   hourStr=hour.Key,
                   uName=hour};
 }

Here are the pertinent parts of my GridView code:

        <asp:GridView ID="GridView1" runat="server" DataSourceID="LinqDataSource1" AutoGenerateColumns="false">
            <asp:TemplateField HeaderText="Sunday">
                <ItemTemplate>
                    <asp:CheckBoxList ID="shiftsSun" runat="server" DataSource='<%#Eval("uName")%>' DataValueField="UserId" />
                </ItemTemplate>
            </asp:TemplateField>
            ...
        </asp:Gridview>

This will correctly display the UserId from the database, but I want it to display the UserName. The only method I've gotten to have this display work is by changing my group statement to:

group x.aspnet_User by x.HourString into hour

I think I'm missing a big concept here. By using group, I should have access to the aspnet_user class members via the uName member of my anonymous class...or so I thought!

edit: Here are a couple screenshots of the variables captured while debugging.

e.Result | aspnet_User

My end goal is to have a gridview which will show a list of work shifts for x hour of y day in each cell. Any design or code help would be greatly appreciated. I can't seem to get my head around this.

+1  A: 

I don't think you're missing any major concepts. The group query produces a collection of IGrouping, where Whatever is the type of the objects in the MilhouseHours collection. (I can't get a bigger picture for your object model.) You then bind those groupings to a CheckBoxList's data source. You're missing a DataTextField="NameField" directive, but no major concepts. Here's some code that works, that's at least related to your problem, if not identical:

        <asp:GridView ID="myGrid" runat="server" AutoGenerateColumns="false">
        <Columns>
            <asp:TemplateField>
                <ItemTemplate>
                    <%# Eval("hourUsers.Key") %>
                </ItemTemplate>
            </asp:TemplateField>

            <asp:TemplateField HeaderText="Sunday">
                <ItemTemplate>
                    <asp:CheckBoxList ID="shiftsSun" runat="server" 
                        DataSource='<%#Eval("hourUsers")%>' 
                        DataTextField = "Name"
                        DataValueField = "Id" />
                </ItemTemplate>
            </asp:TemplateField>
        </Columns>
    </asp:GridView>

And in the pagebehind:

    class UserHour
    {
        public string Name {get;set;}
        public int Id { get; set; }
        public string Hour { get; set; }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        var users = new List<UserHour>
                        {
                                    new UserHour {Name = "Fred", Id = 1, Hour = "0800"},
                                    new UserHour {Name = "Fred", Id = 1, Hour = "0900"},
                                    new UserHour {Name = "Fred", Id = 1, Hour = "1000"},
                                    new UserHour {Name = "Bob", Id = 2, Hour = "0900"},
                                    new UserHour {Name = "Bob", Id = 2, Hour = "1000"},
                        };
        var result = from x in users
                     group x by x.Hour
                     into hour select new
                                          {
                                                      hourStr = hour.Key, hourUsers = hour
                                          };

        myGrid.DataSource = result;
        myGrid.DataBind();
    }
Greg Fleming
I think I've got that concept down. Thanks for answering. What I'm trying to do though is to access members of the aspnet_User object, which should be accessible via the uName portion of my grouping. When reviewing the debug stack, it looks like uName contains a reference to the aspnet_User class but I don't know how to access it. Let me get a screenshot up on my post to clear this up.
ChristopherWright
Ah, I see... The screenshots, as well as this comment, clarify things. I'll edit the above answer.
Greg Fleming
Actually, I'm just going to post a different answer; the edits would be too destructive to be sensible anyway.
Greg Fleming
+2  A: 

The is iterating over a collection that contains MilhouseHour objects: the IGrouping. MilhouseHour does indeed contain a reference to aspnet_User, but the thing that you want to refer to, the name (and the id) is a property of the aspnet_User, not the MilhouseHour. Ideally, you'd be able to write markup like

  <asp:CheckBoxList ID="shiftsSun" runat="server" 
    DataSource='<%#Eval("hourUsers")%>' 
    DataTextField = "aspnet_User.UserName"
    DataValueField = "aspnet_User.UserId" />

But that gives an error. ASP.Net is expecting in the DataTextField the name of a property that it will invoke (presumably by reflection) on the object in question, not an expression to evaluate. The object in question is a MilhouseHour, which doesn't have a property called "aspnet_User.UserName".

You have a number of options.

  1. Do what you did originally, and group x.aspnet_User instead of x in your LINQ expression. Then the thing iterated over by the CheckBoxList will be an IGrouping, which will have properties "UserName" and "UserId" that will work.
  2. Avoid using CheckBoxList and use something that will let you control the code in the inner loop a bit more explicitly, such as repeater:

    <asp:TemplateField HeaderText="Sunday">
    <ItemTemplate>
        <asp:Repeater ID="shiftsSun" runat="server" DataSource='<%#Eval("hourUsers")%>'>
            <ItemTemplate>
                <asp:CheckBox runat="server" 
                   Text='<%# Eval("aspnet_User.UserName")  %>' 
                   Value='<%# Eval("aspnet_User.UserId") %>' />
                <br />
            </ItemTemplate>
        </asp:Repeater>
    </ItemTemplate>
    

There are probably many more options, but that's what occurs to me at the moment.

Greg Fleming
Thank you, Greg! This is a big help.
ChristopherWright