Hi, I followed the guidance provided by Telerik Support in this blog, for a 2 level deep client api driven hierarchical grid, and I modified the code to implement a 3rd level hierarchy following the same pattern.
The blog entry has a zip file you can download for the basic pattern. I created a page called 3levels.aspx which extends the concept to add a 3rd level, and I modified the web service and the lSQL entities to map out a 3rd level of data.
If you load default.aspx from the project you will see the page come up and render very quickly, performing as expected
If you load my 3levels.aspx (see below code) you will see a 20-30 second delay while rendering churns, before the browser responds and renders the markup.
These pages request the data after the page has rendered, so the rendering churn is what's killing the 3rd level grid approach.
Okay you grid masters! Please review and let me know what I can do to work past this issue!
I appreciate any insights!
Thanks and regards!
Scott Burkhalter
SR. SDE Microsoft OEM IT
Dev Lead, Grid Replacement Project
3Levels.aspx - new file add to website
Referenced js file Script1.js - modified to handle 3rd level hierarchy data requests - replaces file in sample site
Modified webservice.asmx including code to obtain 3rd level data:
ListSelector needed for many to many relationship between Orders and Products (put in App_Code) directory as ListSelector.cs
OrderPartial.cs class that addes accessor for Products list hanging off of the Order entity - put in App_Code dir
Modified DataClasses.dbml (LINQ Entities) based on Northwind DB in sample code: - adds 3rd level relationships - replaces same file in App_Code directory
The blog entry has a zip file you can download for the basic pattern. I created a page called 3levels.aspx which extends the concept to add a 3rd level, and I modified the web service and the lSQL entities to map out a 3rd level of data.
If you load default.aspx from the project you will see the page come up and render very quickly, performing as expected
If you load my 3levels.aspx (see below code) you will see a 20-30 second delay while rendering churns, before the browser responds and renders the markup.
These pages request the data after the page has rendered, so the rendering churn is what's killing the 3rd level grid approach.
Okay you grid masters! Please review and let me know what I can do to work past this issue!
I appreciate any insights!
Thanks and regards!
Scott Burkhalter
SR. SDE Microsoft OEM IT
Dev Lead, Grid Replacement Project
3Levels.aspx - new file add to website
| <%@ Page EnableViewState="false" Language="C#" %> |
| <%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" |
| TagPrefix="act" %> |
| <%@ Register TagPrefix="telerik" Namespace="Telerik.Web.UI" Assembly="Telerik.Web.UI" %> |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
| <html xmlns="http://www.w3.org/1999/xhtml"> |
| <head runat="server"> |
| <title>Three level hierarchy</title> |
| <telerik:RadCodeBlock ID="RadCodeBlock1" runat="server"> |
| <script type="text/javascript" src="Script1.js"></script> |
| <script type="text/javascript"> |
| function pageLoad(sender, args) { |
| tableView = $find("<%= RadGrid1.ClientID %>").get_masterTableView(); |
| commandName = "Load" |
| WebService.GetCustomers(0, tableView.get_pageSize(), |
| tableView.get_sortExpressions().toString(), tableView.get_filterExpressions().toDynamicLinq(), |
| updateGrid); |
| } |
| </script> |
| </telerik:RadCodeBlock> |
| </head> |
| <body> |
| <form id="form1" runat="server"> |
| <div> |
| <telerik:RadScriptManager ID="RadScriptManager1" runat="server"> |
| <Services> |
| <asp:ServiceReference Path="~/WebService.asmx" /> |
| </Services> |
| </telerik:RadScriptManager> |
| <telerik:RadStyleSheetManager ID="RadStyleSheetManager1" runat="server" /> |
| <telerik:RadGrid ID="RadGrid1" AllowFilteringByColumn="true" Skin="Telerik" runat="server" |
| GridLines="None" AllowPaging="true" AllowSorting="true" PageSize="10"> |
| <ClientSettings> |
| <ClientEvents OnCommand="RadGrid1_Command" OnHierarchyExpanding="RadGrid1_HierarchyExpanding" /> |
| </ClientSettings> |
| <MasterTableView HierarchyLoadMode="Client" ClientDataKeyNames="CustomerID"> |
| <Columns> |
| <telerik:GridBoundColumn SortExpression="CustomerID" DataField="CustomerID" HeaderText="CustomerID" /> |
| <telerik:GridBoundColumn SortExpression="CompanyName" DataField="CompanyName" HeaderText="CompanyName" /> |
| <telerik:GridBoundColumn SortExpression="ContactName" DataField="ContactName" HeaderText="ContactName" /> |
| <telerik:GridBoundColumn SortExpression="ContactTitle" DataField="ContactTitle" HeaderText="ContactTitle" /> |
| <telerik:GridBoundColumn SortExpression="Country" DataField="Country" HeaderText="Country" /> |
| <telerik:GridBoundColumn SortExpression="City" DataField="City" HeaderText="City" /> |
| </Columns> |
| <NestedViewTemplate> |
| <telerik:RadGrid ID="RadGrid2" AllowFilteringByColumn="true" Skin="Telerik" runat="server" |
| GridLines="None" AllowPaging="true" AllowSorting="true" PageSize="5"> |
| <ClientSettings> |
| <ClientEvents OnCommand="RadGrid2_Command" OnHierarchyExpanding="RadGrid2_HierarchyExpanding" /> |
| </ClientSettings> |
| <MasterTableView HierarchyLoadMode="Client" ClientDataKeyNames="OrderID"> |
| <Columns> |
| <telerik:GridBoundColumn SortExpression="OrderID" DataField="OrderID" HeaderText="OrderID" |
| DataType="System.Int32" /> |
| <telerik:GridBoundColumn SortExpression="OrderDate" DataField="OrderDate" HeaderText="OrderDate" |
| DataType="System.DateTime" DataFormatString="{0:MM/dd/yyyy}" /> |
| <telerik:GridBoundColumn SortExpression="ShipName" DataField="ShipName" HeaderText="ShipName" /> |
| <telerik:GridBoundColumn SortExpression="ShipCity" DataField="ShipCity" HeaderText="ShipCity" /> |
| <telerik:GridBoundColumn SortExpression="ShipCountry" DataField="ShipCountry" HeaderText="ShipCountry" /> |
| </Columns> |
| <NestedViewTemplate> |
| <telerik:RadGrid ID="RadGrid3" AllowFilteringByColumn="true" Skin="Telerik" runat="server" |
| GridLines="None" AllowPaging="true" AllowSorting="true" PageSize="3"> |
| <ClientSettings> |
| <ClientEvents OnCommand="RadGrid3_Command" /> |
| </ClientSettings> |
| <MasterTableView HierarchyLoadMode="Client" ClientDataKeyNames="ProductID"> |
| <Columns> |
| <telerik:GridBoundColumn SortExpression="ProductID" DataField="ProductID" HeaderText="ProductID" |
| DataType="System.Int32" /> |
| <telerik:GridBoundColumn SortExpression="ProductName" DataField="ProductName" HeaderText="ProductName" /> |
| <telerik:GridBoundColumn SortExpression="QuantityPerUnit" DataField="QuantityPerUnit" HeaderText="Quantity PerUnit" DataType="System.String" /> |
| <telerik:GridBoundColumn SortExpression="UnitsOnOrder" DataField="UnitsOnOrder" HeaderText="Units On Order" DataType="System.Int16" /> |
| </Columns> |
| </MasterTableView> |
| <PagerStyle AlwaysVisible="true" /> |
| </telerik:RadGrid> |
| </NestedViewTemplate> |
| </MasterTableView> |
| <PagerStyle AlwaysVisible="true" /> |
| </telerik:RadGrid> |
| </NestedViewTemplate> |
| </MasterTableView> |
| <PagerStyle AlwaysVisible="true" /> |
| </telerik:RadGrid> |
| </div> |
| </form> |
| </body> |
| </html> |
Referenced js file Script1.js - modified to handle 3rd level hierarchy data requests - replaces file in sample site
| var commandName = ""; |
| var tableView = null; |
| var ordersView = null; |
| var productsView = null; |
| var ordersCommandName = ""; |
| var productsCommandName = ""; |
| function RadGrid1_Command(sender, args) { |
| args.set_cancel(true); |
| commandName = args.get_commandName(); |
| WebService.GetCustomers(tableView.get_currentPageIndex() * tableView.get_pageSize(), tableView.get_pageSize(), |
| tableView.get_sortExpressions().toString(), tableView.get_filterExpressions().toDynamicLinq(), |
| updateGrid); |
| } |
| function updateGrid(result) { |
| tableView.set_dataSource(result); |
| tableView.dataBind(); |
| var dataItems = tableView.get_dataItems(); |
| if (commandName == "Filter" || commandName == "Load") { |
| WebService.GetCustomersCount(updateVirtualItemCount); |
| } |
| } |
| function updateVirtualItemCount(result) { |
| tableView.set_virtualItemCount(result); |
| } |
| function RadGrid1_HierarchyExpanding(sender, args) { |
| var customerID = args.getDataKeyValue("CustomerID"); |
| var nestedViewItem = args.get_nestedViewItem(); |
| ordersView = $telerik.findControl(nestedViewItem, "RadGrid2").get_masterTableView(); |
| ordersCommandName = "Load"; |
| WebService.GetOrdersByCustomerID(customerID, ordersView.get_currentPageIndex() * ordersView.get_pageSize(), ordersView.get_pageSize(), |
| ordersView.get_sortExpressions().toString(), ordersView.get_filterExpressions().toDynamicLinq(), |
| updateOrdersGrid, updateFailed); |
| } |
| function updateOrdersGrid(result) { |
| ordersView.set_dataSource(result); |
| ordersView.dataBind(); |
| if (ordersCommandName == "Filter" || ordersCommandName == "Load") { |
| WebService.GetOrdersByCustomerIDCount(updateOrdersVirtualItemCount); |
| } |
| } |
| function updateFailed(ex) { |
| alert(ex.get_message()); |
| } |
| function updateOrdersVirtualItemCount(result) { |
| ordersView.set_virtualItemCount(result); |
| } |
| function RadGrid2_Command(sender, args) { |
| ordersView = sender.get_masterTableView(); |
| var nestedViewItem = sender.get_element().parentNode.parentNode; |
| var parentGridDataItem = $find(Telerik.Web.UI.Grid.GetNodePreviousSiblingByTagName(nestedViewItem, "tr").id); |
| var customerID = parentGridDataItem.getDataKeyValue("CustomerID"); |
| args.set_cancel(true); |
| ordersCommandName = args.get_commandName(); |
| WebService.GetOrdersByCustomerID(customerID, ordersView.get_currentPageIndex() * ordersView.get_pageSize(), ordersView.get_pageSize(), |
| ordersView.get_sortExpressions().toString(), ordersView.get_filterExpressions().toDynamicLinq(), |
| updateOrdersGrid, updateFailed); |
| } |
| function RadGrid2_HierarchyExpanding(sender, args) { |
| var orderID = args.getDataKeyValue("OrderID"); |
| var nestedViewItem = args.get_nestedViewItem(); |
| productsView = $telerik.findControl(nestedViewItem, "RadGrid3").get_masterTableView(); |
| productsCommandName = "Load"; |
| WebService.GetProductsByOrderID(orderID, productsView.get_currentPageIndex() * productsView.get_pageSize(), productsView.get_pageSize(), |
| productsView.get_sortExpressions().toString(), productsView.get_filterExpressions().toDynamicLinq(), |
| updateEmployeesGrid, updateFailed); |
| } |
| function updateEmployeesGrid(result) { |
| productsView.set_dataSource(result); |
| productsView.dataBind(); |
| if (productsCommandName == "Filter" || productsCommandName == "Load") { |
| WebService.GetEmployeesByEmployeeIDCount(updateOrdersVirtualItemCount, updateFailed); |
| } |
| } |
| function updateOrdersVirtualItemCount(result) { |
| ordersView.set_virtualItemCount(result); |
| } |
| function RadGrid3_Command(sender, args) { |
| productsView = sender.get_masterTableView(); |
| var nestedViewItem = sender.get_element().parentNode.parentNode; |
| var parentGridDataItem = $find(Telerik.Web.UI.Grid.GetNodePreviousSiblingByTagName(nestedViewItem, "tr").id); |
| var orderID = parentGridDataItem.getDataKeyValue("OrderID"); |
| args.set_cancel(true); |
| productsCommandName = args.get_commandName(); |
| WebService.GetProductsByOrderID(orderID, productsView.get_currentPageIndex() * productsView.get_pageSize(), productsView.get_pageSize(), |
| productsView.get_sortExpressions().toString(), productsView.get_filterExpressions().toDynamicLinq(), |
| updateEmployeesGrid, updateFailed); |
| } |
Modified webservice.asmx including code to obtain 3rd level data:
| <%@ WebService Language="C#" Class="WebService" %> |
| using System; |
| using System.Web; |
| using System.Web.Services; |
| using System.Web.Services.Protocols; |
| using System.Linq; |
| using System.Linq.Dynamic; |
| using System.Collections.Generic; |
| [WebService(Namespace = "http://tempuri.org/")] |
| [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] |
| // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. |
| [System.Web.Script.Services.ScriptService] |
| public class WebService : System.Web.Services.WebService |
| { |
| IQueryable<Customer> customers = new DataClassesDataContext().Customers.AsQueryable<Customer>(); |
| IQueryable<Order> orders = new DataClassesDataContext().Orders.AsQueryable<Order>(); |
| IQueryable<Order_Detail> order_details = new DataClassesDataContext().Order_Details.AsQueryable<Order_Detail>(); |
| IQueryable<Product> products = new DataClassesDataContext().Products.AsQueryable<Product>(); |
| [WebMethod(EnableSession = true)] |
| public List<Customer> GetCustomers(int startIndex, int maximumRows, string sortExpression, string filterExpression) |
| { |
| if (!String.IsNullOrEmpty(filterExpression)) |
| { |
| customers = customers.Where(filterExpression); |
| } |
| if (!String.IsNullOrEmpty(sortExpression)) |
| { |
| customers = customers.OrderBy(sortExpression); |
| } |
| HttpContext.Current.Session["CustomersCount"] = customers.Count(); |
| return customers.Skip(startIndex).Take(maximumRows).ToList(); |
| } |
| [WebMethod(EnableSession = true)] |
| public int GetCustomersCount() |
| { |
| return (int)HttpContext.Current.Session["CustomersCount"]; |
| } |
| [WebMethod(EnableSession = true)] |
| public List<Order> GetOrdersByCustomerID(string customerID, int startIndex, int maximumRows, string sortExpression, string filterExpression) |
| { |
| if (!String.IsNullOrEmpty(filterExpression)) |
| { |
| orders = orders.Where(String.Format(@"CustomerID == ""{0}"" AND {1}", customerID, filterExpression)); |
| } |
| else |
| { |
| orders = orders.Where(c => c.CustomerID == customerID); |
| } |
| if (!String.IsNullOrEmpty(sortExpression)) |
| { |
| orders = orders.OrderBy(sortExpression); |
| } |
| HttpContext.Current.Session["OrdersByCustomerCount"] = orders.Count(); |
| foreach (var o1 in orders) |
| o1.Order_Details = null; |
| return orders.Skip(startIndex).Take(maximumRows).ToList(); |
| } |
| [WebMethod(EnableSession = true)] |
| public int GetOrdersByCustomerIDCount() |
| { |
| return (int)HttpContext.Current.Session["OrdersByCustomerCount"]; |
| } |
| [WebMethod(EnableSession = true)] |
| public List<ProductPOCO> GetProductsByOrderID(string orderID, int startIndex, int maximumRows, string sortExpression, string filterExpression) |
| { |
| if (!String.IsNullOrEmpty(filterExpression)) |
| { |
| orders = orders.Where(String.Format(@"OrderID == ""{0}"" AND {1}", orderID, filterExpression)); |
| } |
| else |
| { |
| orders = orders.Where(o => o.OrderID == Int32.Parse(orderID)); |
| } |
| if (!String.IsNullOrEmpty(sortExpression)) |
| { |
| orders = orders.OrderBy(sortExpression); |
| } |
| HttpContext.Current.Session["ProductsByOrderIDCount"] = orders.FirstOrDefault().Products.Count(); |
| var q = from p in orders.FirstOrDefault().Products |
| select new ProductPOCO |
| { |
| ProductID = p.ProductID, |
| ProductName = p.ProductName, |
| QuantityPerUnit = p.QuantityPerUnit, |
| UnitsOnOrder = p.UnitsOnOrder |
| }; |
| return q.Skip(startIndex).Take(maximumRows).ToList(); |
| } |
| [WebMethod(EnableSession = true)] |
| public int GetEmployeesByEmployeeIDCount() |
| { |
| return (int)HttpContext.Current.Session["ProductsByOrderIDCount"]; |
| } |
| public class ProductPOCO |
| { |
| public int ProductID { get; set; } |
| public string ProductName { get; set; } |
| public string QuantityPerUnit { get; set; } |
| public short? UnitsOnOrder { get; set; } |
| } |
| } |
ListSelector needed for many to many relationship between Orders and Products (put in App_Code) directory as ListSelector.cs
| using System; |
| using System.Collections.Generic; |
| using System.Linq; |
| using System.Text; |
| using System.Collections; |
| using System.ComponentModel; |
| namespace ListSelector |
| { |
| public class BindingListSelector<TSource, T> : ListSelector<TSource, T>, IBindingList |
| { |
| public BindingListSelector(IBindingList source, Func<TSource, T> selector):base(source as IList<TSource>, selector) |
| { |
| sourceAsBindingList = source; |
| } |
| protected IBindingList sourceAsBindingList; |
| #region IBindingList Members |
| public void AddIndex(PropertyDescriptor property) |
| { |
| sourceAsBindingList.AddIndex(property); |
| } |
| public object AddNew() |
| { |
| return sourceAsBindingList.AddNew(); |
| } |
| public bool AllowEdit |
| { |
| get { return sourceAsBindingList.AllowEdit; } |
| } |
| public bool AllowNew |
| { |
| get { return sourceAsBindingList.AllowNew; } |
| } |
| public bool AllowRemove |
| { |
| get { return sourceAsBindingList.AllowRemove; } |
| } |
| public void ApplySort(PropertyDescriptor property, ListSortDirection direction) |
| { |
| sourceAsBindingList.ApplySort(property, direction); |
| } |
| public int Find(PropertyDescriptor property, object key) |
| { |
| return sourceAsBindingList.Find(property, key); |
| } |
| public bool IsSorted |
| { |
| get { return sourceAsBindingList.IsSorted; } |
| } |
| public event ListChangedEventHandler ListChanged |
| { |
| add |
| { |
| sourceAsBindingList.ListChanged += value; |
| } |
| remove |
| { |
| sourceAsBindingList.ListChanged -= value; |
| } |
| } |
| public void RemoveIndex(PropertyDescriptor property) |
| { |
| sourceAsBindingList.RemoveIndex(property); |
| } |
| public void RemoveSort() |
| { |
| sourceAsBindingList.RemoveSort(); |
| } |
| public ListSortDirection SortDirection |
| { |
| get { return sourceAsBindingList.SortDirection; } |
| } |
| public PropertyDescriptor SortProperty |
| { |
| get { return sourceAsBindingList.SortProperty; } |
| } |
| public bool SupportsChangeNotification |
| { |
| get { return sourceAsBindingList.SupportsChangeNotification; } |
| } |
| public bool SupportsSearching |
| { |
| get { return sourceAsBindingList.SupportsSearching; } |
| } |
| public bool SupportsSorting |
| { |
| get { return sourceAsBindingList.SupportsSorting; } |
| } |
| #endregion |
| } |
| public static class ListSelectorExtensions |
| { |
| public static ListSelector<TSource, T> AsListSelector<TSource, T>(this IList<TSource> source, Func<TSource, T> selector) |
| { |
| return new ListSelector<TSource, T>(source, selector); |
| } |
| public static BindingListSelector<TSource, T> AsListSelector<TSource, T>(this IBindingList source, Func<TSource, T> selector) |
| { |
| return new BindingListSelector<TSource, T>(source, selector); |
| } |
| } |
| public class ListSelector<TSource, T> : IList<T>, IList |
| { |
| public ListSelector(IList<TSource> source, Func<TSource, T> selector) |
| { |
| this.source = source; |
| this.selector = selector; |
| projection = source.Select(selector); |
| } |
| protected IList<TSource> source; |
| protected Func<TSource, T> selector; |
| protected IEnumerable<T> projection; |
| #region IList<T> Members |
| public int IndexOf(T item) |
| { |
| int i = 0; |
| foreach (T t in projection) |
| { |
| if (t.Equals(item)) |
| return i; |
| i++; |
| } |
| return -1; |
| } |
| public void Insert(int index, T item) |
| { |
| throw new Exception("The method or operation is not implemented."); |
| } |
| public void RemoveAt(int index) |
| { |
| throw new Exception("The method or operation is not implemented."); |
| } |
| public T this[int index] |
| { |
| get |
| { |
| return selector(source[index]); |
| } |
| set |
| { |
| throw new Exception("The method or operation is not implemented."); |
| } |
| } |
| #endregion |
| #region ICollection<T> Members |
| public void Add(T item) |
| { |
| throw new Exception("The method or operation is not implemented."); |
| } |
| public void Clear() |
| { |
| throw new Exception("The method or operation is not implemented."); |
| } |
| public bool Contains(T item) |
| { |
| return projection.Contains(item); |
| } |
| public void CopyTo(T[] array, int arrayIndex) |
| { |
| //source.CopyTo(projection.ToArray(), arrayIndex); |
| } |
| public int Count |
| { |
| get { return source.Count; } |
| } |
| public bool IsReadOnly |
| { |
| get { return true; } |
| } |
| public bool Remove(T item) |
| { |
| throw new Exception("The method or operation is not implemented."); |
| } |
| #endregion |
| #region IEnumerable<T> Members |
| public IEnumerator<T> GetEnumerator() |
| { |
| return projection.GetEnumerator(); |
| } |
| #endregion |
| #region IEnumerable Members |
| System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() |
| { |
| return projection.GetEnumerator(); |
| } |
| #endregion |
| #region IList Members |
| int IList.Add(object value) |
| { |
| throw new Exception("The method or operation is not implemented."); |
| } |
| void IList.Clear() |
| { |
| throw new Exception("The method or operation is not implemented."); |
| } |
| bool IList.Contains(object value) |
| { |
| return Contains((T) value); |
| } |
| int IList.IndexOf(object value) |
| { |
| return IndexOf((T) value); |
| } |
| void IList.Insert(int index, object value) |
| { |
| throw new Exception("The method or operation is not implemented."); |
| } |
| bool IList.IsFixedSize |
| { |
| get { return true; } |
| } |
| bool IList.IsReadOnly |
| { |
| get { return true; } |
| } |
| void IList.Remove(object value) |
| { |
| throw new Exception("The method or operation is not implemented."); |
| } |
| void IList.RemoveAt(int index) |
| { |
| throw new Exception("The method or operation is not implemented."); |
| } |
| object IList.this[int index] |
| { |
| get |
| { |
| return this[index]; |
| } |
| set |
| { |
| throw new Exception("The method or operation is not implemented."); |
| } |
| } |
| #endregion |
| #region ICollection Members |
| void ICollection.CopyTo(Array array, int index) |
| { |
| //CopyTo(array, index); |
| } |
| int ICollection.Count |
| { |
| get { return this.Count; } |
| } |
| bool ICollection.IsSynchronized |
| { |
| get { return false; } |
| } |
| object ICollection.SyncRoot |
| { |
| get { throw new Exception("The method or operation is not implemented."); } |
| } |
| #endregion |
| } |
| } |
OrderPartial.cs class that addes accessor for Products list hanging off of the Order entity - put in App_Code dir
| using System; |
| using System.Collections.Generic; |
| using System.Linq; |
| using System.Web; |
| using ListSelector; |
| public partial class Order |
| { |
| private ListSelector<Order_Detail, Product> products = null; |
| public ListSelector<Order_Detail, Product> Products |
| { |
| get |
| { |
| if (products == null) |
| products = this.Order_Details.AsListSelector(od => od.Product); |
| return products; |
| } |
| } |
| } |
Modified DataClasses.dbml (LINQ Entities) based on Northwind DB in sample code: - adds 3rd level relationships - replaces same file in App_Code directory
| <?xml version="1.0" encoding="utf-8"?> |
| <Database Name="NorthwindDB" Class="DataClassesDataContext" xmlns="http://schemas.microsoft.com/linqtosql/dbml/2007"> |
| <Connection Mode="WebSettings" ConnectionString="Data Source=scburk1;AttachDbFilename=|DataDirectory|\Northwind.mdf;Initial Catalog=NorthwindDB;Integrated Security=True" SettingsObjectName="System.Configuration.ConfigurationManager.ConnectionStrings" SettingsPropertyName="NorthwindDBConnectionString" Provider="System.Data.SqlClient" /> |
| <Table Name="dbo.Customers" Member="Customers"> |
| <Type Name="Customer"> |
| <Column Name="CustomerID" Type="System.String" DbType="NChar(5) NOT NULL" CanBeNull="false" /> |
| <Column Name="CompanyName" Type="System.String" DbType="NVarChar(40) NOT NULL" CanBeNull="false" /> |
| <Column Name="ContactName" Type="System.String" DbType="NVarChar(30)" CanBeNull="true" /> |
| <Column Name="ContactTitle" Type="System.String" DbType="NVarChar(30)" CanBeNull="true" /> |
| <Column Name="Address" Type="System.String" DbType="NVarChar(60)" CanBeNull="true" /> |
| <Column Name="City" Type="System.String" DbType="NVarChar(15)" CanBeNull="true" /> |
| <Column Name="Region" Type="System.String" DbType="NVarChar(15)" CanBeNull="true" /> |
| <Column Name="PostalCode" Type="System.String" DbType="NVarChar(10)" CanBeNull="true" /> |
| <Column Name="Country" Type="System.String" DbType="NVarChar(15)" CanBeNull="true" /> |
| <Column Name="Phone" Type="System.String" DbType="NVarChar(24)" CanBeNull="true" /> |
| <Column Name="Fax" Type="System.String" DbType="NVarChar(24)" CanBeNull="true" /> |
| <Association Name="Customer_Order" Member="Orders" ThisKey="CustomerID" OtherKey="CustomerID" Type="Order" /> |
| </Type> |
| </Table> |
| <Table Name="dbo.Orders" Member="Orders"> |
| <Type Name="Order"> |
| <Column Name="OrderID" Type="System.Int32" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" /> |
| <Column Name="CustomerID" Type="System.String" DbType="NChar(5)" CanBeNull="true" /> |
| <Column Name="EmployeeID" Type="System.Int32" DbType="Int" CanBeNull="true" /> |
| <Column Name="OrderDate" Type="System.DateTime" DbType="DateTime" CanBeNull="true" /> |
| <Column Name="RequiredDate" Type="System.DateTime" DbType="DateTime" CanBeNull="true" /> |
| <Column Name="ShippedDate" Type="System.DateTime" DbType="DateTime" CanBeNull="true" /> |
| <Column Name="ShipVia" Type="System.Int32" DbType="Int" CanBeNull="true" /> |
| <Column Name="Freight" Type="System.Decimal" DbType="Money" CanBeNull="true" /> |
| <Column Name="ShipName" Type="System.String" DbType="NVarChar(40)" CanBeNull="true" /> |
| <Column Name="ShipAddress" Type="System.String" DbType="NVarChar(60)" CanBeNull="true" /> |
| <Column Name="ShipCity" Type="System.String" DbType="NVarChar(15)" CanBeNull="true" /> |
| <Column Name="ShipRegion" Type="System.String" DbType="NVarChar(15)" CanBeNull="true" /> |
| <Column Name="ShipPostalCode" Type="System.String" DbType="NVarChar(10)" CanBeNull="true" /> |
| <Column Name="ShipCountry" Type="System.String" DbType="NVarChar(15)" CanBeNull="true" /> |
| <Association Name="Order_Order_Detail" Member="Order_Details" ThisKey="OrderID" OtherKey="OrderID" Type="Order_Detail" /> |
| <Association Name="Customer_Order" Member="Customer" ThisKey="CustomerID" OtherKey="CustomerID" Type="Customer" IsForeignKey="true" /> |
| </Type> |
| </Table> |
| <Table Name="dbo.[Order Details]" Member="Order_Details"> |
| <Type Name="Order_Detail"> |
| <Column Name="OrderID" Type="System.Int32" DbType="Int NOT NULL" IsPrimaryKey="true" CanBeNull="false" /> |
| <Column Name="ProductID" Type="System.Int32" DbType="Int NOT NULL" IsPrimaryKey="true" CanBeNull="false" /> |
| <Column Name="UnitPrice" Type="System.Decimal" DbType="Money NOT NULL" CanBeNull="false" /> |
| <Column Name="Quantity" Type="System.Int16" DbType="SmallInt NOT NULL" CanBeNull="false" /> |
| <Column Name="Discount" Type="System.Single" DbType="Real NOT NULL" CanBeNull="false" /> |
| <Association Name="Order_Order_Detail" Member="Order" ThisKey="OrderID" OtherKey="OrderID" Type="Order" IsForeignKey="true" /> |
| <Association Name="Product_Order_Detail" Member="Product" ThisKey="ProductID" OtherKey="ProductID" Type="Product" IsForeignKey="true" /> |
| </Type> |
| </Table> |
| <Table Name="dbo.Products" Member="Products"> |
| <Type Name="Product"> |
| <Column Name="ProductID" Type="System.Int32" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" /> |
| <Column Name="ProductName" Type="System.String" DbType="NVarChar(40) NOT NULL" CanBeNull="false" /> |
| <Column Name="SupplierID" Type="System.Int32" DbType="Int" CanBeNull="true" /> |
| <Column Name="CategoryID" Type="System.Int32" DbType="Int" CanBeNull="true" /> |
| <Column Name="QuantityPerUnit" Type="System.String" DbType="NVarChar(20)" CanBeNull="true" /> |
| <Column Name="UnitPrice" Type="System.Decimal" DbType="Money" CanBeNull="true" /> |
| <Column Name="UnitsInStock" Type="System.Int16" DbType="SmallInt" CanBeNull="true" /> |
| <Column Name="UnitsOnOrder" Type="System.Int16" DbType="SmallInt" CanBeNull="true" /> |
| <Column Name="ReorderLevel" Type="System.Int16" DbType="SmallInt" CanBeNull="true" /> |
| <Column Name="Discontinued" Type="System.Boolean" DbType="Bit NOT NULL" CanBeNull="false" /> |
| <Association Name="Product_Order_Detail" Member="Order_Details" ThisKey="ProductID" OtherKey="ProductID" Type="Order_Detail" /> |
| </Type> |
| </Table> |
| </Database> |