EntityDataSource accessing a collection from another entity in GridView - asp.net

I'm not sure if my title accurately describes what I'm trying to do.
I have two tables in my Entity Framework, person and user. I am trying to display a grid of users, so I set up this EntityDatasource:
<asp:EntityDataSource ID="peopleQuery" runat="server"
ConnectionString="name=myEntities" DefaultContainerName="myEntities"
EnableFlattening="False" EntitySetName="people" Include="location"
Where="it.active = 1" OrderBy="it.lastname, it.firstname">
</asp:EntityDataSource>
Now in my GridView, I can bind to fields like lastname, firstname, emailaddress, and fields from the location table like address and city.
Now, in my system, a user record can be attached to one or more person records. So it's a 1-to-many relationship. In the gridview, I would like to display the users associated with each person. I can do it with a RowDataBound event, but that requires an extra DB lookup for every row in the database.
Is there some efficient way to navigate from the "many" end of a "1-to-many" foreign key relationship?
Actually, it doesn't even have to be 1-to-many. It could be 1-to-1, but you're on the other end of the foreign key relationship. So, in this example, the EntityDataSource uses the "person" table, but in the user table, I have a personid field. So the foreign key is user.personid => person.personid. Since the GridView is driven from the user person table, how can I navigate to the user table to display user.username in my GridView?

You can nest either a gridview or repeater inside your Gridview and use the relationship to populate the data by setting the datasource to the relationship:
<asp:EntityDataSource ID="eds" runat="server"
ContextTypeName="people"
EnableFlattening="False"
EntitySetName="people"
Include="users" >
</asp:EntityDataSource>
<asp:GridView ID="gv" runat="server" AutoGenerateColumns="False" DataKeyNames="PeopleId" DataSourceID="eds">
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="First name" />
<asp:BoundField DataField="LastName" HeaderText="Last name" />
<asp:TemplateField HeaderText="People">
<ItemTemplate>
<asp:Repeater ID="rptUsers" runat="server" DataSource='<%# Eval("users") %>'>
<ItemTemplate>
<%# Eval("username") %>
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
This assumes you have a relationship setup in your data model, eg:
public class person(){
public int PersonId{get;set;}
public string FirstName{ get;set;}
public string LastName{ get;set;}
pubic virtual ICollection<user> users { get; set; }
}
public class user(){
public int UserId{ get;set;}
public string username{ get;set; }
}

Related

How to load Data from a second table in GridView

i have to tables: Users and PrivateMessages.
Users has UserID and Username.
PrivateMessages has the coloumns PMID and Text and SenderID.
(of course it has much more but to explain the problem, its enough)
Now I have a DataSource and a method like this:
public static List<UserPM> GetAllPMsAsSender(Guid userID)
{
using (RPGDataContext dc = new RPGDataContext())
{
return (from a in dc.UserPMs where a.Sender == userID && !a.IsDeletedSender orderby a.Timestamp select a).ToList();
}
}
and bind it to the ObjectDataSource with is bound to the Grid View.
The Grid view now looks like these:
<asp:ObjectDataSource ID="odsOutcome" runat="server"
SelectMethod="GetAllPMsAsSender" TypeName="DAL.PMDAL">
<SelectParameters>
<asp:CookieParameter CookieName="UserID" DbType="Guid" Name="userID" />
</SelectParameters>
</asp:ObjectDataSource>
<asp:GridView ID="gridOut" runat="server" AutoGenerateColumns="False"
DataSourceID="odsOutcome">
<Columns>
<asp:BoundField DataField="PMID" HeaderText="PMID" SortExpression="PMID" />
<asp:BoundField DataField="Text" HeaderText="Text" SortExpression="Text"/>
<asp:BoundField DataField="UserID" HeaderText="UserID" SortExpression="UserID" />
</Columns>
</asp:GridView>
So how I can get the Username in this field instead the UserID?
Try using join and select the user name too for your object data source and use the user name to display it instead of user id.
Refer this link How to do a join in linq to sql with method syntax?

The EntityKey property can only be set when the current value of the property is null with n-tier web applicaiton

I am working with n-tier web application with Entity Framework with ObjectDataSource.
In my web application there are Complains & WorkOrder entities which has many to one or zero relationship.
When a WorkOrder is added user can select for which complain it is for. This is what i tried to do.
<asp:DetailsView ID="DVComplain" runat="server"
DefaultMode="Insert" AutoGenerateInsertButton="True"
AutoGenerateRows="False" DataSourceID="ODSAddWorkOrder"
oniteminserting="DetailsView1_ItemInserting" >
<Fields>
<asp:TemplateField HeaderText="Complain">
<InsertItemTemplate>
<asp:DropDownList ID="DDLComplain" runat="server" DataTextField="ComplainID"
DataValueField="ComplainID" DataSourceID="EDSComplains"
oninit="DDLComplain_Init">
</asp:DropDownList>
<asp:CheckBox ID="CBIsWOOfComplain" runat="server"
oninit="CBIsWOOfComplain_Init" />
<asp:EntityDataSource ID="EDSComplains" runat="server"
ConnectionString="name=MMEntities" DefaultContainerName="MMEntities"
EnableFlattening="False" EntitySetName="ComplainMasters"
EntityTypeFilter="ComplainMaster" Select="it.[ComplainID]" OrderBy="it.ComplainID">
</asp:EntityDataSource>
</InsertItemTemplate>
</asp:TemplateField>
<asp:BoundField HeaderText="WOGeneratedDate" DataField="WOGeneratedDate" DataFormatString="yyyy-MM-dd" />
.......
</Fields>
</asp:DetailsView>
<asp:ObjectDataSource ID="ODSAddWorkOrder" runat="server"
DataObjectTypeName="MiantenanceManager.DAL.WorkOrder" TypeName="MiantenanceManager.BLL.WorkOrderBL"
InsertMethod="addWorkOrder">
</asp:ObjectDataSource>
And add the following code to DetailView ItemInserting method.
protected void DVWorkOrder_ItemInserting(object sender, DetailsViewInsertEventArgs e)
{
if (_CBIsWOOfComplain.Checked)
{
using (complainBL)
{
e.Values["Complain"] = complainBL.getComplianByID(_DDLComplains.SelectedValue);
}
}
}
Note: complainBL implements the IDispose.
In WorkOrederBL call it calls the WorkOrderRepository class which invokes the following method which throws the exception mention in the subject.
context.WorkOrder.AddObject(workOrder);
context.SaveChanges();
How can i overcome this problem. Is my approch is wrong??
The reason why you are getting thi serror is thet AddObject is for adding new objects. An object that has an entity key represents an existing row in the database. This assumes that you are using database generated keys for your tables.
There are different ways to fix it, for example:
Option 1: Get the record from the database, update the fields on that record, then save changes.
Option 2: Create a new object with the entity key, attach it to the context with state modified, then save changes.

Set SelectedValue of DropDownList inside DataGrid

I got a datagrid where a datasource #1 is bound to, e.g.
public class Class
{
public string Val { get; set; }
public string Val2 { get; set; }
}
List<Class> classes = new List<Class>();
dgr.DataSource = classes;
Inside this datagrid i got a listbox for each row with a datasource #2 bound to:
<Columns>
<asp:TemplateColumn HeaderText="Spaltenname">
<ItemTemplate>
<asp:ListBox runat="server" DataTextField="Text" DataValueField="Value" DataSource="<%#oParentTablesHandler.DataTableXYZ%>" />
</ItemTemplate>
</asp:TemplateColumn>
</Columns>
This works, but I have problems setting the SelectedValue.
SelectedValue="<%# "" %>
will work but I need a selection depending on Val from datasource #1. How can I do that? I need to use Eval i guess, but
SelectedValue="<%# Eval("Val") %> did not work...
edit: I found out that I want to select an item by text and not by value, argh. Is there a way to do that?
Try like this..
<%# ((Class)Container.DataItem).Val %>
UPDATE:
well.there may be some value in 'Val' property that may not exist in your Datasource#2's corresponding column...
So for test purpose try following..
<asp:ListBox .. AppendDataBoundItems="true">
<Items>
<asp:ListItem Text="NA" Value="" />
</Items>
</asp:ListBox >

Custom button in DetailsView updates value in Database

I'm trying to practice and started with small game. Users can register and so on.
Now I have no idea how to perform user to "work", I have GridView and DetailsView, in GridView user selects company and it displays in DetailsView. In DetailsView I have custom button with "work" title. In database I have Table with default value of "300 dollar". And when user click on custom button "work" in DetailsView I want change the value in the database, something like 300+400 dollar = 700. dollar. So the new updated value needs to be 700. I tried to perform it and can't find solution.
I have .aspx page with "salary" label and custom button.
asp:DetailsView ID="DetailsView1" runat="server".....
<ItemTemplate>
<asp:Label ID="Label5" runat="server" Text="Salary($):" Font-Size="Small" ForeColor="#9F9B9B"></asp:Label>
<asp:Label ID="lblSalary" runat="server" Text='<%# Bind("Salary") %>'></asp:Label>
</ItemTemplate>
<asp:TemplateField ShowHeader="False">
<ItemTemplate>
<asp:Button ID="BtnWork" runat="server" CausesValidation="false" CommandName=""
Text="Work" OnClick="BtnWork_Click" />
</ItemTemplate>
</asp:TemplateField>
And aspx.cs page:
protected void BtnWork_Click(object sender, EventArgs e)
{
MembershipUser currentUser = Membership.GetUser();
Guid currentUserId = (Guid)currentUser.ProviderUserKey;
string ConnectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
string sql = "SELECT * FROM Custon_MoneyWork WHERE UserId=#UserId";
}
It sounds like you don't need/want the DetailsView to do the update since the value is not coming from the user and you are using a custom button and not an update on the DetailsView. If that is the case, you can simple use a SqlCommand and execute the update in the button click event handler that you stubbed out in your post.
If this was not your goal, let me know, and I'll do my best to suggest another option.

Binding Gridview to IList<BusinessObject> that contains an IList<BusinessObject>

I'm having trouble figuring out how to bind a custom IList to a gridview. The IList contains another custom IList. I need to bind a property from this IList to the gridview.
public class Seminar : BusinessObject
{
private string _description = String.Empty;
private List<User> _attendees;
public string Description {get {return _description;} set {_description = value;}}
public List<User> Attendees {get {return _attendees;} set {_attendees = value;}}
}
public class User : BusinessObject
{
private string _name = String.Empty;
public string Name { get { return _name; } set { _name = value; } }
}
Backend page.aspx.cs:
List<Seminar> seminarList = SeminarManager.Get(id);
gridSeminars.DataSource = seminarList;
gridSeminars.DataBind();
Frontend page.aspx:
<asp:GridView ID="gridSeminars" runat="server">
<Columns>
<asp:BoundField DataField="Id" />
<asp:BoundField DataField="Description" />
<asp:BoundField DataField="Name" />
</Columns>
</asp:GridView>
The problem is with populating the "Name" field in the gridview. All suggestions are welcome.
Have you tried,
Attendees.Name
Edit:
Attendees is an IEnumerable itself. The above suggestion only works with Attendee.Name
If you wan´t to display all the attendees you need to make a templatefield and maybe use a repeater or something...something like:
<asp:TemplateField>
<ItemTemplate>
<asp:Repeater runat="server" DataSource='<%# Eval("Attendees") %>'>
<ItemTemplate>
<tr>
<td>
Name
</td>
<td>
<%# Eval("Name")%>
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:TemplateField>
Johan's answer is a good one, specifically the part about how you are trying to bind a collection to a column that is expecting something that can be converted to a string.
Another option would be to put a TemplateField that contains the bindable control (Repeater, another GridView, etc.) you choose to use and binding the DataSource property to the Attendees property of your business object.
Also, I don't if you're married to the idea of using a GridView, but in cases like these where you need more control of the layout, I would suggest the new ListView (.NET 3.5) control, or lately I've just been using nested repeaters so I can have more refined control of the layout I am trying to generate.
Hope this helps.
I'm assuming you want to flatten the hierarchy and display one row for every user. If you have access to Linq, you can use this:
List<Seminar> seminarList = SeminarManager.Get(id);
gridSeminars.DataSource = from seminar in seminarList // loop through all of the seminars in the list
from user in seminar.Attendees // loop through all of the users in the current seminar
select new // create a new, flattened object to bind to.
{
seminar.Id,
seminar.Description,
user.Name
};
gridSeminars.DataBind();
http://weblogs.asp.net/zeeshanhirani/archive/2008/03/26/select-many-operator-part-1.aspx

Resources