Fransiscus Setiawan | EV Charging & Azure Solution Architect | Sydney

Technical Insights: Azure, .NET, Dynamics 365 & EV Charging Architecture

Simple LINQ Tutorial

I’ve started learning about LINQ because I need to keep up to date with the latest technology out there. I’ve created a simple Business Layer which interact directly with Linq to SQL(DBML). It includes Insert, Update, Delete, Select and paging with LINQ.

Hopefully this tutorial will be useful enough for someone who is going to learn about LINQ. With LINQ we can really simplify/integrate the stored procedure into our Code base but it doesn’t mean LINQ does not support Stored Procedure.

It supports Stored Procedure as well since we might use Stored Procedure for complex calculation. You don’t need to create a table adapter anymore since LINQ does everything the same as table adapter.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LinqCore.Factories
{
    public class GroupFactory
    {

        /// 
        /// this is used to get all the groups
        /// 
        /// 
        public IQueryable GetAllGroups()
        {
            GroupsDataContext db = new GroupsDataContext();
            var groups = from g in db.Groups
                         select g;

            return groups;
        }

        /// 
        /// this is used to get the group based on the group id
        /// 
        /// 
        /// 
        public Group GetGroup(int groupid)
        {
            GroupsDataContext db = new GroupsDataContext();

            var groups = from g in db.Groups
                         where (g.GroupID == groupid)
                         select g;

            return groups.SingleOrDefault();
        }

        /// 
        /// this is used to insert Or Update which determined by the nullable
        /// integer value of the groupID
        /// 
        /// 
        /// 
        /// 
        public void GroupUpdate(int? groupID, string groupName, bool valid)
        {
            GroupsDataContext db = new GroupsDataContext();
            Group group = new Group();

            if (groupID.HasValue)
            {
               group = db.Groups.Single(p => p.GroupID == groupID.Value);
            }

            group.GroupName = groupName;
            group.valid = valid;

            if (!groupID.HasValue)
            {
                db.Groups.InsertOnSubmit(group);
            }
            db.SubmitChanges();
        }

        /// 
        /// this is used to delete a group based on its ID
        /// 
        /// 
        public void GroupDelete(int groupID)
        {
            GroupsDataContext db = new GroupsDataContext();

            Group group = db.Groups.Single(p => p.GroupID == groupID);
            db.Groups.DeleteOnSubmit(group);
            db.SubmitChanges();
        }

        /// 
        /// this is used to do paging for the returned result
        /// 
        /// 
        /// 
        /// 
        public IQueryable GetAllGroups(int startIndex, int pageSize)
        {
            GroupsDataContext db = new GroupsDataContext();
            var groups = from g in db.Groups
                         select g;

            return groups.Skip(startIndex).Take(pageSize);
        }
    }
}

Using temp table and SQL stored procedure in Table Adapter

I was having a problem when adding a stored procedure into table adapter. The error was “Invalid object” of my temporary table name inside stored procedure.

It’s a bit strange since what i thought the table adapter only care about the results being returned but what it is actually checking up the existence of the table it self. FMTONLY is used to “Returns only metadata to the client. Can be used to test the format of the response without actually running the query”.

--uncomment this to regenerate it in table adapter
--comment it once you are done with generating the table adapter
SET FMTONLY OFF

File Stream/Stream response in AJAX Update Panel

Last few months, I got a problem to place a button to generate a CSV file in the update panel. I was having a problem related with response error. So what i did was to place the button outside the Update Panel. Today, I found a simple solution to place this button inside the AJAX Update panel

1. You need to set the page mode on the page load event

protected void Page_Load(object sender, EventArgs e)
{
    this.Page.Form.Enctype = "multipart/form-data";
}

2. set the update Panel Children as trigger to true


3. set the trigger to your button


   

Self Recursive Deleting On self foreign key sql server

I’ve been assigned a task to delete data from a table with a subtree structure which means the foreign key can be contained in another rows in the same table. It’s a self contained foreign key on the same table.

Theoritically when it comes to my mind, i was thinking of recursive delete. But how????I’ve tried to google about it, I found this article from Microsoft. These are coming from Microsoft Article as well.

These are the dummy data that you can play around with in your DB

CREATE TABLE Employees
(empid int NOT NULL,
 mgrid int NULL,
 empname varchar(25) NOT NULL,
 salary money NOT NULL,
 CONSTRAINT PK_Employees_empid PRIMARY KEY(empid))

INSERT INTO employees(empid, mgrid, empname, salary)
  VALUES( 1, NULL, 'Nancy',  $10000.00)

INSERT INTO employees(empid, mgrid, empname, salary)
  VALUES( 2,    1, 'Andrew',  $5000.00)

INSERT INTO employees(empid, mgrid, empname, salary)
  VALUES( 3,    1, 'Janet',   $5000.00)

INSERT INTO employees(empid, mgrid, empname, salary)
  VALUES( 4,    1, 'Margaret',$5000.00)

INSERT INTO employees(empid, mgrid, empname, salary)
  VALUES( 5,    2, 'Steven',  $2500.00)

INSERT INTO employees(empid, mgrid, empname, salary)
  VALUES( 6,    2, 'Michael', $2500.00)

INSERT INTO employees(empid, mgrid, empname, salary)
  VALUES( 7,    3, 'Robert',  $2500.00)

INSERT INTO employees(empid, mgrid, empname, salary)
  VALUES( 8,    3, 'Laura',   $2500.00)

INSERT INTO employees(empid, mgrid, empname, salary)
  VALUES( 9,    3, 'Ann',     $2500.00)

INSERT INTO employees(empid, mgrid, empname, salary)
  VALUES(10,    4, 'Ina',     $2500.00)

INSERT INTO employees(empid, mgrid, empname, salary)
  VALUES(11,    7, 'David',   $2000.00)

INSERT INTO employees(empid, mgrid, empname, salary)
  VALUES(12,    7, 'Ron',     $2000.00)

INSERT INTO employees(empid, mgrid, empname, salary)
  VALUES(13,    7, 'Dan',     $2000.00)

INSERT INTO employees(empid, mgrid, empname, salary)
  VALUES(14,   11, 'James',   $1500.00)

I’m going to delete employee no 3(Janet) which means it need to delete 7(Robert),8(Laura),9(Ann) and 11(David),12(Ron),13(Dan), 14(James) based on the managerial structure level.

What you need to do is to create a trigger for cascading delete

CREATE TRIGGER trg_d_employees_on_delete_cascade ON Employees FOR DELETE
AS

IF EXISTS(SELECT *
          FROM
              Employees AS E
            JOIN
              deleted   AS D ON E.mgrid = D.empid)

  DELETE FROM Employees
  FROM
      Employees AS E
    JOIN
      deleted   AS D ON E.mgrid = D.empid

  GO

It will self join based on the deleted table. It’s not finish yet, you need to set the recursive trigger to active by executing command like

ALTER DATABASE DMO
SET RECURSIVE_TRIGGERS ON

Action Time:

DELETE FROM employees WHERE empid = 3

and you will see that it deletes all the subordinates of Janet

How to remove checked item in Checked Box List

At the moment, I’m learning towards win development. I got a very simple problem which is “Removing checked item on checked box list”. The first code below is throwing an error since you try to delete an item then on the postback it will reset the index. The real solution is on the second code

//this code is throwing an error about the index position
 private void btnRemove_Click(object sender, EventArgs e)
        {
            foreach (SMSData item in chkSmsList.CheckedItems)
            {
                chkSmsList.Items.Remove(item);
            }
        }

Fix

//this is the code which is working perfectly, basically this code always looking into the first item on the "CheckedItems" Stack
  private void btnRemove_Click(object sender, EventArgs e)
        {
            while (chkSmsList.CheckedItems.Count > 0)
            {
                chkSmsList.Items.Remove(chkSmsList.CheckedItems[0]);
            }
        }

Filtering Field/Column in DataTable

I was having a problem when I have the same datatable and one datagrid but I want to display different field on the grid for different report and I want to use AutoGenerateColumn = true in the datagrid. Remember, it is about filtering fields not Row(If you want to filter row then you can use dataview).

This is the way of filtering field in datatable

     public static DataTable FilterTableRemoveColumns(tdsReports.ReportSelectDataTable inputTable, List fields)
        {
            //create a new data table
            DataTable newTable = new DataTable();
            newTable.TableName = "newtable";

            //iterate through each column
            foreach (DataColumn col in inputTable.Columns)
            {
                //cross match and filter fields/column
                if (fields.Contains(col.ColumnName))
                {
                    //create a new datacolumn with the same column name and same datatype
                    DataColumn newCol = new DataColumn(col.ColumnName, col.DataType);
                    newTable.Columns.Add(newCol);
                }
            }

            //you ignore the schema because you don't want to throw the exception
            //you merge the data with the new schema
            newTable.Merge(inputTable, true, MissingSchemaAction.Ignore);
            return newTable;
        }

this is how you use it. You pass a string list into the function. The string list contains your desired column

Private Function FilterDataTableColumn(ByVal dtReport As tdsReports.ReportSelectDataTable) As DataTable

        Dim dt As DataTable = New DataTable()
        Try
            Dim list As List(Of String) = New List(Of String)

            If (ReportType = Enums.ReportType.DispatchedOrdersReport) Then
                list.Add("OrderID")
                list.Add("PaymentType")
                list.Add("ProductCode")
                list.Add("Qty")
                list.Add("Price")
                list.Add("Total")
                list.Add("IncGst")

            ElseIf (ReportType = Enums.ReportType.MonthySalesReport) Then
                list.Add("Qty")
                list.Add("ProductCode")
                list.Add("ProductName")

            ElseIf (ReportType = Enums.ReportType.OrderReport) Then
                list.Add("ProductCode")
                list.Add("Qty")
                list.Add("ProductName")

            End If

            dt = objReportService.FilterTableRemoveColumns(dtReport, list)

        Catch ex As Exception

        End Try

        Return dt
    End Function

Set Default value with clear text for input type=”password”

Normally we have two text boxes which is user name and password. On the first load of the page we want to set the default value of user name text box becoming ‘username’ and set the default value of password text box becoming ‘password’ not ‘*******’.

Well what most of us think that we can use javascript to change the type of the input box?well I’ve got this trick to have two textboxes in the same location and swap it with “OnFocus” event

  
            

    

Set the default value for username text box via code behind

      Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            txtUserName.Attributes.Add("onfocus", "JavaScript:if(this.value=='username'){this.value=''};")
            txtUserName.Attributes.Add("onblur", "JavaScript:if(this.value==''){this.value='username'};")
            txtUserName.Attributes.Add("value", "username")

            txtPassword.Attributes.Add("onkeydown", _
                                            "javascript:if((event.which && event.which == 13) || " _
                                            + "(event.keyCode && event.keyCode == 13))" _
                                            + " {document.getElementById('" + btnLogin.ClientID + "').click(); " _
                                            + " return false; } else return true;")
        End Sub

Temporary View using Common Table Expression In Sql server 2005

In this post, I will discuss on how to optimize join. Based on my experience. When you join record you need to join as fewer as possible otherwise it will result in performance. And please make sure you put the index on the key that you are using for join.

Within SQL Server 2005, You can use temporary view, It is not a table variable and it is not a temporary table. You also need to try to avoid cursor as well if possible.

First sample is a traditional join where I joined all the tables that required. In this sample EvenResult table has 20 million rows and I need to count the evenresult table based on the EventID that I get from the join criteria.

1. Join all tables./Traditional Way and it takes about 21secs

    SELECT
                E.EventID
            FROM
                Events E
            INNER JOIN
                Venues V
            ON
                E.VenueID = V.VenueID
            INNER JOIN
                Regions R
            ON
                R.RegionID = V.RegionID
            INNER JOIN
                EventResults er
            ON
                E.EventID = er.EventID
            WHERE
                (DATEDIFF(d, E.EventDate, @DateFrom) = 0)
            AND
                ((@StateID IS NULL) OR (R.StateID = @StateID))
            AND
                ((@RegionID IS NULL) OR (R.RegionID = @RegionID))
            AND
                ((@VenueID IS NULL) OR (V.VenueID = @VenueID))
            AND
                ((@EventScheduleID IS NULL) OR (E.EventScheduleID = @EventScheduleID))

2. Using Temporary Views, In this query. I try to filter down all the required eventID based on the criteria and insert it into a temporary view(tblEvents). Once i get the filtered result then I joined it with EventResults table and It takes only 16secs considering the number of records.

WITH tblEvents(EventID) AS
(
            SELECT
                E.EventID
            FROM
                Events E
            INNER JOIN
                Venues V
            ON
                E.VenueID = V.VenueID
            INNER JOIN
                Regions R
            ON
                R.RegionID = V.RegionID
            WHERE
                (DATEDIFF(d, E.EventDate, @DateFrom) = 0)
            AND
                ((@StateID IS NULL) OR (R.StateID = @StateID))
            AND
                ((@RegionID IS NULL) OR (R.RegionID = @RegionID))
            AND
                ((@VenueID IS NULL) OR (V.VenueID = @VenueID))
            AND
                ((@EventScheduleID IS NULL) OR (E.EventScheduleID = @EventScheduleID))
)

            SELECT
                COUNT(*) As Total
            FROM
                tblEvents te
            INNER JOIN
                EventResults er
            ON
                te.EventID = er.EventID
            GROUP BY
                er.MemberID
            HAVING
                COUNT(*) >= @MinGame
            AND
                COUNT(*) <= @MaxGame

Error System.NotSupportedException: The given path’s format is not supported

I got this exception when i tried to uploading a file to a web and try to save it as a different name

System.NotSupportedException: The given path’s format is not supported.
at System.Security.Util.StringExpressionSet.CanonicalizePath(String path, Boolean needFullPath)
at

By using code below it will make sure that you will get the real file name without any trailing path, fuCSV is a file upload control and there is a property file name but it doesn’t guarantee that you will get the actual file name. When i tried to debug it, it also give me the file path. The best way of doing this is to use GetFileName method from System.IO.Path

It was:

string filename = fuCSV.PostedFile.FileName;

Fix

string filename = System.IO.Path.GetFileName(fuCSV.PostedFile.FileName);

Record/Row Filter in DataTable

When I have a smaller rows return from my sql stored procedure, I tend to think of not recreating another stored procedure to do filtering or to use optional parameter. My idea is to do filtering from the code base and not recreating/adding the stored procedure.

The idea was to create a generic stored procedure without any filter and apply the filter from the code base. The example given is by applying filter to dataset and then after that add the datatable to dataset and then cast it back again to the datatable.

  public tdsEvent.EventSummaryDataTable TodayEventSummaryFilter(string filter)
        {
            tdsEvent.EventSummaryDataTable table = TodayEventSummaryCache();
            DataRow[] rows = table.Select(filter); //apply the filter first

            if (rows.Length != 0)
            {
                DataSet ds = new DataSet();

                tdsEvent.EventSummaryDataTable eventTable = new tdsEvent.EventSummaryDataTable();
                ds.Tables.Add(eventTable); // add to the filter
                ds.Merge(rows, false, MissingSchemaAction.Ignore);
                // cast it back to the data table
                table = ds.Tables[0] as tdsEvent.EventSummaryDataTable;
            }
            else
            {
                table = new tdsEvent.EventSummaryDataTable();
            }

            return table;
        }

This is the alternative code which doing the same thing as above

Dim table as tdsEvent.EventSummaryDataTable = TodayEventSummaryCache()
//create dataview instance based on datatable

dim dv as DataView = new DataView(table)

//create the filter to select the valid only
dv.RowFilter = "Valid = 1"

//bind to the grid or repeater
rptEvent.Datasource = dv
rptEvent.DataBind()

Page 16 of 19

Powered by WordPress & Theme by Anders Norén