ASP.NET 2.0: How to bind an asp:Menu to an SqlDataSource? - asp.net

i've found how to bind an asp:Menu to XML. i've found how to bind an asp:Menu to a site map (which is really binding it to XML). How do you bind an asp:Menu to a database?
The .NET Framework provides multiple data sources:
HierarchicalDataSourceControl
XmlDataSource
SiteMapDataSource
DataSourceControl
SqlDataSource
AccessDataSource
LinqDataSource
i want to use one that represents data from an SQL Server table. The data is stored in the standard hierarchical format that everyone uses:
NodeID ParentNodeID Caption Url
======== ============== ========= =================
{3234... {3632... stackoverflow http://stackov...
{3632... (null) Questions ~/questions.aspx
{3233... (null) Tags ~/tags.aspx
{3235... {3632... google http://www.goo...
And the query to return all the rows would be:
SELECT * FROM Nodes
What is the secret method that Microsoft intended me to use to mash that data into an asp:Menu?
Update: There is a good article on aspalliance.com: Building a Database Driven Hierarchical Menu using ASP.NET 2.0. Unfortunatly it describes how to perform XML data binding; while i'm interested in database binding.

There is a good article on aspalliance.com: Building a Database Driven Hierarchical Menu using ASP.NET 2.0. Each step is explained and nicely illustrated.
"In this article, Michael demonstrates how to create a database driven hierarchical menu with only a few lines of code using ASP.NET 2.0. This is a must read tutorial for everyone who needs a professional menu that is powerful and flexible with simplistic design."
The code for could be:
protected void LoadData()
{
DataSet ds = new DataSet();
string connStr = YOUR_CONNECTION_STRING_HERE;
using(SqlConnection conn = newSqlConnection(connStr))
{
string sql = "Select NodeID, Caption, Url, ParentID from Menu";
SqlDataAdapter da = newSqlDataAdapter(sql, conn);
da.Fill(ds);
da.Dispose();
}
ds.DataSetName = "Menus";
ds.Tables[0].TableName = "Menu";
DataRelation relation = newDataRelation("ParentChild",
ds.Tables["Menu"].Columns["NodeID"],
ds.Tables["Menu"].Columns["ParentID"], true);
relation.Nested = true;
ds.Relations.Add(relation);
xmlDataSource.Data = ds.GetXml();
}

The menu does not support binding to SqlDataSource because it is a HierarchicalDataBoundControl - only hierarchical datasources are supported. You should implement your own HierarchicalDataSourceControl. Check here for an example. Alternatively you could create a custom sitemap provider and use the SiteMapDataSource as demonstrated here. Finally you can use a 3'rd party control which can bind to SqlDataSource.

Related

Dynamics CRM Entity Data update from a custom Aspx Page

I have found many sample to create data in dynamics crm from a custom aspx page, but i need to update entity data.
any sample will be helpful.
Thanks
It's quite simple, when you create a record normally you use the following code:
Entity newContact = new Entity("contact");
contact["firstname"] = "John";
contact["lastname"] = "Smith";
service.Create(newContact);
If you need to update a record, you need to retrieve it first (using a Retrieve if you have the Guid, or a RetrieveMultiple if you need to find it using a query), after just update the fields.
Entity retrievedContact = service.Retrieve("contact", GuidOfTheRecord, ColumnsYouWantToRetrieve);
retrievedContact["firstname"] = "My New First Name";
retrievedContact["lastname"] = "My New Last Name";
service.Update(retrievedContact);

Entity Framework Update Time & Date Column with Parameterized

I have changed all my code from the raw ADO.NET SQLCommand to Entity Framework in order to have easier accessibility of changing my code in the future. However, I have realized there are many drawbacks in Entity Framework it is not as simple as injecting raw SQL commands into the database. Moreover, I have used Reverse Engineering to generate the Models & Mapping for MS Sql Server.
Currently, I am trying to do the following but none of the columns are getting updated.
string sql = #"UPDATE [ProductDB] SET CreatedProduct_Time=getdate(), CreatedProduct_Date=getdate()" + " WHERE [Material_No] = #Material_No";
db.Database.ExecuteSqlCommand(sql, new SqlParameter("#Material_No", materialnotxt));
The columns are not getting updated.
I am having a doubt whether Entity Framework will help me maintain my code for future use and is it worth the headache using it instead of the old raw SQL code? So far there are many constraints and it requires a higher learning curve.
Some confusing parts I have find online what is the difference between the context.Database.ExecuteSqlCommand and this MSDN http://msdn.microsoft.com/en-us/library/bb738684.aspx the code looks entirely different then my approach.
EDIT
I have used a different approach to insert the Date and Time while inserting all the info from the textbox.
using (var db = new ROGContext())
{
ProductDB product = new ProductDB
{
Material_No = long.Parse(MaterialNo_txtbox.Text),
Product_Line = ProductLineDropDownList1.SelectedItem.Text,
Product_Description = Description_txtbox.Text,
Size = Size_txtbox.Text,
UOM = UOM_txtbox.Text,
SupplierID = long.Parse(SupplierCountryListBox.SelectedItem.Value),
CreatedProduct_Date = DateTime.Parse(System.DateTime.Now.ToShortDateString()), //in the SQL database I have set the datatype as date to get yyyy/mm/dd
CreatedProduct_Time = DateTime.Now.TimeOfDay //in the SQL database I have set the datatype as time(0) to get hh:mm:ss
};
long queryselect = (from materialno in db.ProductDBs
where materialno.Material_No == product.Material_No
select materialno.Material_No).SingleOrDefault();
if (queryselect != long.Parse(materialnotxt))
{
Label1.Text = "Product successfully added in database";
Label1.Visible = true;
db.ProductDBs.Add(product);
db.SaveChanges();
}
You can use Context.ExecuteStoreCommand for Insert, Update and Delete.
See in Page 64 of Entity Framework 4.0 Recipes: A Problem-Solution Approach
Answer your edited part:
ExecuteStoreQuery for Select
ExecuteStoreCommand for Insert, Update and Delete
Entity Framework v4 – Tips and Tricks

Creating Reports in ASP.Net with Entity Framework

We are looking to add Microsoft Reports - SSRS to one of our internal websites.
The database has all the reporting features installed.
The website is using Entity Framework 4 for all data.
I have been able to create a report using the old fashioned way of creating a DataSet (*.XSD) and this works well.
My question though, is it possible to utilise the existing Entity Framework in the site for the data required by the reports? Rather than having to re-invent the wheel and make a whole DataSet, along with relationships etc..
It's a website and not application, so this (http://weblogs.asp.net/rajbk/archive/2010/05/09/creating-an-asp-net-report-using-visual-studio-2010-part-1.aspx) doesn't seem to apply; I don't see the DataSource (in part 2 of the tutorial)
Update
As a side-note, we would like to steer clear of expensive third-party controls etc.
Also, another way to look at the issue might be to generate the *.XSD from the entity framework entity model; is this possible? It's not ideal though would get us up and running..
Below is a quick sample of how i set the report datasource in one of my .NET winForms applications.
public void getMyReportData()
{
using (myEntityDataModel v = new myEntityDataModel())
{
var reportQuery = (from r in v.myTable
select new
{
l.ID,
l.LeaveApplicationDate,
l.EmployeeNumber,
l.EmployeeName,
l.StartDate,
l.EndDate,
l.Supervisor,
l.Department,
l.Col1,
l.Col2,
.......,
.......,
l.Address
}).ToList();
reportViewer1.LocalReport.DataSources.Clear();
ReportDataSource datasource = new ReportDataSource("nameOfReportDataset", reportQuery);
reportViewer1.LocalReport.DataSources.Add(datasource);
Stream rpt = loadEmbededReportDefinition("Report1.rdlc");
reportViewer1.LocalReport.LoadReportDefinition(rpt);
reportViewer1.RefreshReport();
//Another way of setting the reportViewer report source
string exeFolder = Path.GetDirectoryName(Application.ExecutablePath);
string reportPath = Path.Combine(exeFolder, #"rdlcReports\Report1.rdlc");
reportViewer1.LocalReport.ReportPath = reportPath;
reportParameter p = new ReportParameter("DeptID", deptID.ToString());
reportViewer1.LocalReport.SetParameters(new[] { p });
}
}
public static Stream loadEmbededReportDefinition(string reportName)
{
Assembly _assembly = Assembly.GetExecutingAssembly();
Stream _reportStream = _assembly.GetManifestResourceStream("ProjectNamespace.rdlcReportsFolder." + reportName);
return _reportStream;
}
My approach has always been to use RDLC files with object data sources and run them in 'local' mode. These data sources are ... my entities! This way, I'm using all of the same business logic, string formatting, culture awareness, etc. that I use for my web apps. There are a some quirks, but I've been able to live with them:
RDLC files don't like to live in web projects. We create a separate dummy winform project and add the RDLC files there.
I don't show reports in a viewer. I let the user download a PDF, Word, or Excel file and choose to save or open in the native viewer. This saves a bunch of headaches, but can put some folks off, depending on requirements. For mobile devices, it's pretty nice.
Since you are not using SSRS, you don't get the nice subscription feature. You are going to build that, if required. In many ways, though, I prefer this.
However, the benefits are really nice:
I'm using all of the same business logic goodness that I've already written for my views.
I have a custom ReportActionResult and DownloadReport controller method that allows me to essentially run any report via a single URL. This can be VERY handy. It sure makes a custom subscription component easier.
Report development seems to go pretty quick, now that I only need to adjust entity partial classes to tweak a little something here or there. Also - If I need to shape the data just a bit differently, I have LINQ.
We too use SSRS as "local" reports. We create Views in SQL server, then create that Object in our application along with the other EF Domain Models, and query that object using our DbContext. We use an ASPX page and use the code behind (Page_Load) to get the data passed to the report.
Here is an example of how we query it in the Page_Load Event:
var person = MyDbContext
.Query<ReportModel>()
.Where(x => x.PersonId == personId)
.Where(x => x.Year == year)
.Select(x =>
{
PersonId = x.PersonId,
Year = x.Year,
Name = x.Name
});
var datasource = new ReportDataSource("DataSet1", person.ToList());
if (!Page.IsPostBack)
{
myReport.Visible = true;
myReport.ProcessingMode = ProcessingMode.Local;
myReport.LocalReport.ReportPath = #"Areas\Person\Reports\PersonReport.rdlc";
}
myReport.LocalReport.DataSources.Clear();
myReport.LocalReport.DataSources.Add(datasource);
myReport.LocalReport.Refresh();
The trick is to create a report (.rdlc) with a blank data source connection string, a blank query block and a blank DataSetInfo (I had to modify the xml manually). They must exist in file and be blank as follows:
SomeReport.rdlc (viewing as xml)
...
<DataSources>
<DataSource Name="conx">
<ConnectionProperties>
<DataProvider />
<ConnectString />
</ConnectionProperties>
<rd:DataSourceID>19f59849-cdff-4f18-8611-3c2d78c44269</rd:DataSourceID>
</DataSource>
</DataSources>
...
<Query>
<DataSourceName>conx</DataSourceName>
<CommandText />
<rd:UseGenericDesigner>true</rd:UseGenericDesigner>
</Query>
<rd:DataSetInfo>
<rd:DataSetName>SomeDataSetName</rd:DataSetName>
</rd:DataSetInfo>
now in a page event, I use a SelectedIndexChanged on a DropDownList, bind the report datasource as follows:
protected void theDropDownList_SelectedIndexChanged(object sender, EventArgs e)
{
if (theDropDownList.SelectedIndex == 0)
return;
var ds = DataTranslator.GetRosterReport(Int64.Parse(theDropDownList.SelectedValue));
_rvReport.LocalReport.ReportPath = "SomePathToThe\\Report.rdlc";
_rvReport.LocalReport.DataSources.Add(new ReportDataSource("SomeDataSetName", ds));
_rvReport.Visible = true;
_rvReport.LocalReport.Refresh();
}
You can use a WCF-Service as Datasource and so re-use your application data and logic for your report. This requires a SQL-server standard edition at least i believe. So no can do with the free SQL-express edition.
You can use LINQ with RDLC Report which is quite easy to use
LinqNewDataContext db = new LinqNewDataContext();
var query = from c in db.tbl_Temperatures
where c.Device_Id == "Tlog1"
select c;
var datasource = new ReportDataSource("DataSet1", query.ToList());
ReportViewer1.Visible = true;
ReportViewer1.ProcessingMode = ProcessingMode.Local;
ReportViewer1.LocalReport.ReportPath = #"Report6.rdlc";
ReportViewer1.LocalReport.DataSources.Clear();
ReportViewer1.LocalReport.DataSources.Add(datasource);
ReportViewer1.LocalReport.Refresh();

Setting values when a user updates a record using Entity Framework 4 and VB.NET in ASP.NET application

this is my first post, hopefully I'm following the rules!
After a few weeks of banging my head against brick walls and endless hours of internet searches, I have decided I need to make my own post and hopefully find the answers and guidance from all you experts.
I am building an ASP.NET application (in Visual Studio 2010) which uses an SQL 2008 database and Entity Framework 4 to join the two parts together. I designed the database as a database project first, then built the Entity Model as a class project which is then referenced in the main ASP.NET project. I believe this is called Database First in Entity Framwork terms?
I'm fairly new to Web Apps (I mainly develop WinForms apps) and this is my first attempt at using Entity Framwork.
I can just about understand C# so any code samples or snippets you might supply would be preferred in VB if possible.
To give some background on where I am so far. I built a regsitration page called register.aspx and created a wizard style form using ASP:Wizard with ASP:TextBox, ASP:DropdownList and ASP:CheckBoxList it's all laid out inside a HTML table and uses CSS for some of the formatting. Once the user gets the the last page in the wizard and presses "Finish" I execute some code in the VB code behind file as follows:
Protected Sub wizardRegister_FinishButtonClick(sender As Object, e As System.Web.UI.WebControls.WizardNavigationEventArgs) Handles wizardRegister.FinishButtonClick
Dim context As New CPMModel.CPMEntities
Dim person As New CPMModel.Person
Dim employee As New CPMModel.Employee
Dim newID As Guid = Guid.NewGuid
With person
.ID = newID
.UserID = txbx_UserName.Text
.Title = ddl_Title.SelectedValue
.FirstName = txbx_FirstName.Text
.MiddleInitial = txbx_MiddleInitial.Text
.FamilyName = txbx_FamilyName.Text
.Gender = ddl_Gender.SelectedValue
.DOB = txbx_DOB.Text
.RegistrationDate = Date.Now
.RegistrationMethod = "W"
.ContactMethodID = New Guid(ddl_ContactMethodList.SelectedValue)
.UserName = txbx_UserName.Text
If Not (My.Settings.AuthenticationUsingAD) Then
.Password = txbx_Password.Text ' [todo] write call to salted password hash function
End If
.IsRedundant = False
.IsLocked = False
End With
context.AddToPeople(person)
With employee
.ID = newID
.PayrollNumber = txbx_PayrollNumber.Text
.JobTitle = txbx_JobTitle.Text
.DepartmentID = ddl_DepartmentList.SelectedValue
.OfficeNumber = txbx_OfficeNumber.Text
.HomeNumber = txbx_HomeNumber.Text
.MobileNumber = txbx_MobileNumber.Text
.BleepNumber = txbx_BleepNumber.Text
.OfficeEmail = txbx_OfficeEmail.Text
.HomeEmail = txbx_HomeEmail.Text
.IsRedundant = False
.RedundantDate = Nothing
'--------------------------
.FiledBy = Threading.Thread.CurrentPrincipal.Identity.Name
.FiledLocation = My.Computer.Name
.FiledDateTimeStamp = Date.Now
'----------------------------
End With
context.AddToEmployees(employee)
context.SaveChanges()
End Sub
The above works fine, seemed to be a sensible way of doing it (remember I'm new to Entity Framework) and gave me the results I extpected.
I have another page called manage.aspx on this page is a tab control, each tab page contains a asp:DetailsView which is bound to an asp:EntityDataSource, I have enabled Update on all the Entity Data Sources and on some I have also enabled Insert, none of the have delete enabled.
If I build and run the app at this stage everything works fine, you can press the "edit" link make changes and then press "update" and sure enough those updates are displayed on the screen instantly and the database does have the correct values in.
Here's the problem, I need to intercept the update in the above code (the bold bit) notice there is a column in my database called FiledBy, FiledLocation, and FiledDateTimeStamp. I don't want to show these columns to the user viewing the ASP.NET page but I want to update them when the user presses update (if there were any changes made). I have tried converting the ASP:DetailsView into a template and then coding the HTML side with things like;
<## Eval(User.Name) #>
I did manage to get it to put the correct values in the textboxes when in edit mode but I had the following problems;
It didn't save to the database
I have to show the textboxes which I don't want to do
I have read on several other posts on here and other websites that you can override the SaveChanges part of the Entity Framwork model one example of this is in the code below;
public override int SaveChanges()
{
var entities = ChangeTracker.Entries<YourEntityType>()
.Where(e => e.State == EntityState.Added)
.Select(e => e.Entity);
var currentDate = DateTime.Now;
foreach(var entity in entities)
{
entity.Date = currentDate;
}
return base.SaveChanges();
}
The problem is, that whilst I understand the idea, and can just about transalate it to VB I have no idea how to implement this. Where do I put the code? How do I call the code? etc.
I would ideally like to find a solution that meets the following requirements:
Doesn't get overwritten if I was to regenerate / update the Entity Model
Doesn't need to be copy and pasted for every table in my model (most but not all have the audit columns in)
Can be used for other columns, for example, if a user make a selection in a check list I may want to write some value into another (not exposed to the user) column.
Am I taking the right approach to displaying data in may webpages I certainly find the DataView and GridView limiting, I did think about creating a form like the registration form in table tags but have no Idea how to populate the textboxes etc with values from the database nor how to implement paging as many of the tables have one to many relationships, although saving changes would be easy if I did populate textboxes on a table.
Thank you all in advance to anyone who offers there support.
Kevin.
Ok so I have now got closer, but still not got it working correctly. I've used the following code to edit the value in the DetailsView on the Databound event. If writes the correct timestamp into the read only textbox but does not right this value back to the database when you press the Update button on the DetailsView control.
Protected Sub dv_Employee_DataBound(sender As Object, e As EventArgs) Handles dv_Employee.DataBound
If dv_Employee.CurrentMode = DetailsViewMode.Edit Then
For Each row In dv_Employee.Rows
If row.Cells(0).Text = "FiledDateTimeStamp" Then
row.Cells(1).Text = Date.Now()
End If
Next
End If
End Sub
I like the idea of overriding the save changes method. Your context should be a partial class, so you just need to define another class marked as partial with the same name in the same namespace and add the override to it.
Namespace CPMModel
Partial Public Class CPMEntities
...Your override here
End Class
Since this is an override of the default SaveChanges method you do not need to make any changes in how it is called. You will need to find a way to gain access to entity level properties.
Since this is the method that commits changes for all entities you will not be able to access the properties like you do in your example, since the entity class does not define an of your concrete properties. So you need to create partial classes for your entities and have them all implement an interface that defines the properties you would like to interact with.
Create interface:
Interface IDate
Property Date() as DateTime
End Interface
Create partial class for each of your entities that implements the IDate interface. (The same rules apply for these partial classes they must be marked partial, have the same name as the class they extend and live in the same namespace) Then in your SaveChanges override
public override int SaveChanges()
{
var entities = ChangeTracker.Entries<Entity>()
.Where(e => e.State == EntityState.Added)
.Select(e => e.Entity);
var currentDate = DateTime.Now;
foreach(var entity in entities)
{
***Now cast entity to type of IDate and set your value ***
entity.Date = currentDate;
}
return base.SaveChanges();
}
I don't write in Vb so I left the syntax in C#.
That should fulfill all of your requirements.
Ok, so this isn't exactly how I imagined it would work but it has infact met my needs. Kind of!
What I did was Write a Protected Sub in the code behind file of the aspx file.
Protected Sub CustomEntityUpdate_Employee(sender As Object, e As
EntityDataSourceChangingEventArgs)
Dim emp As CPMModel.Employee = e.Entity
' Check if the entity state is modified and update auditing columns
If emp.EntityState = EntityState.Modified Then
emp.FiledDateTimeStamp = Date.Now()
emp.FiledBy = Threading.Thread.CurrentPrincipal.Identity.Name
emp.FiledLocation = My.Computer.Name
End If
End Sub
Then in the aspx page I edited the Entity datasource code to call the above sub routine
#nUpdating="CustomEntityUpdate_Employee"
<asp:EntityDataSource
ID="eds_Employee"
runat="server"
ConnectionString="name=CPMEntities"
DefaultContainerName="CPMEntities"
EnableFlattening="False"
EnableUpdate="True"
EntitySetName="Employees"
AutoGenerateWhereClause="True"
Where=""
EntityTypeFilter="Employee"
**OnUpdating="CustomEntityUpdate_Employee">**
<WhereParameters>
<asp:SessionParameter
Name="ID"
SessionField="UserID" />
</WhereParameters>
</asp:EntityDataSource>
The Protected Sub, checks if the entity has been modified and if it has updates the entity auditing columns with the values I wanted.
It works but it will certainly make for a lot more code, I ideally would like a way to package this up perhaps into a class and just call the sub from the various aspx pages via the OnUpdating event and have the class figure out which entity was making the call and handle all the logic there.

DataTableMapping using adapter.FillSchema method applied on a Stored Procedure

this is a method i was reading about #MSDN ,
my question is if for an example i would like to use it on a stored procedure
with the fact that the query of that stored procedure is already specifying columns to select from the table like following :
SELECT Columnsome, columnother, , , , ...FROM thisSQLdbTable
though i would like to implement the approach of that specific method , it seems very advanced from a little research i have made on
"the best way" available to extract data from SQL Server into Asp.net DataTable.
public static DataTable GetCustomerData(string dataSetName,
string connectionString)
{
DataTable table = new DataTable(dataSetName);
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlDataAdapter adapter = new SqlDataAdapter(
"SELECT CustomerID, CompanyName, ContactName FROM dbo.Customers", connection);
DataTableMapping mapping = adapter.TableMappings.Add("Table", "Customers");
mapping.ColumnMappings.Add("CompanyName", "Name");
mapping.ColumnMappings.Add("ContactName", "Contact");
connection.Open();
adapter.FillSchema(table, SchemaType.Mapped);
adapter.Fill(table);
return table;
}
}
or is it not the method to use if i am querying via SP that specifies the selected column
i could actually drop that stored procedure if it is not requiered to select /specify columns
the stored procedure is doing a specific calculation and updates the table with results of calculation then i am switching it's "MODE" to select results from the table that was updated.
what i did is recyceling (; giving it a parameter (bit type)
stored procedure then asks for the value of supplied bool / bit Parameter,
if its is status true it updates (doing its original task it was made for)
if its false its doing a select oporation so i am using it as i would with 2 separated commands
but now that i have search for a better way to extract data from db into a Data table
i give up on the two way SP and i will make a selection via the exaple above if they're not intended to be used thogether as with my current SP that does preselection when servs the GetCustomersData() above.
So the question is do i need to let the function to make the selection or can i serve it with my sp ready made selection to implemet it with GetCustomersData() in the way that it will only do rest of task and only mapp the columns that was preselected
Still a bit confused on your actual requirement but here goes:
I See you are using a direct query in your C# code, 'best way' would be to make a SP out of it then say:
SqlCommand command = conn.CreateCommand();
SqlDataAdapter sqlAdapter = new SqlDataAdapter(command);
command.CommandType = System.Data.CommandType.StoredProcedure;
command.CommandText = "sp_GetCustomerData";
Then after you have added parameters if needed do:
conn.Open();
sqlAdapter.Fill(dtResult);
conn.Close();
Where dtResult is Datatable.
So you do not need to do any mapping in this case, and since you are using a SP from the Database it will work faster than your direct query and you can change the query logic any time without the need of re deploying your code.
Stored procedures are perfectly valid in this use case. however, if you want more of a properly mapped table, you have several options, some of which go beyond the use of DataTables.
You can use strongly typed DataSets or perhaps use an ORM (object relational mapper).
ref: Typed Datasets: http://msdn.microsoft.com/en-us/library/esbykkzb(v=vs.71).aspx
ref: What is an ORM : http://en.wikipedia.org/wiki/Object-relational_mapping
EXAMPLES OF ORM'S
ref: Entity Framework : http://msdn.microsoft.com/en-us/data/ef.aspx
ref: NHibernate: http://nhforge.org/

Resources