Friday, February 10, 2012

How to convert List to DataTable

very recently I have published a new article based on "How to convert DataTable to generic List"

Now I have discussed about the vice verse -"convert List to DataTable"

Solution:

Here we use PropertyDescriptor ComponentModel class.

public static DataTable ToDataTable<T>(this IList<T> data)
{
PropertyDescriptorCollection properties =
TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
foreach (PropertyDescriptor prop in properties)
table.Columns.Add(
prop.Name,
(prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
? Nullable.GetUnderlyingType(prop.PropertyType)
: prop.PropertyType
);
foreach (T item in data)
{
DataRow row = table.NewRow();
foreach (PropertyDescriptor prop in properties)
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
table.Rows.Add(row);
}
return table;
}

"The project type is not supported by this installation"

Today I have faced this problem when try to open a VS2010 project which is covert from VS2008 project. FYI:This project was built by another developer.

After conversion open the solution it gave me the following error,"The project type is not supported by this installation"

Possible Cause:It may possible that lack some advanced frameworks like newer versions of Windows Mobile SDK, but IIRC error message in such case is different.Or may be some updated packages required Or Visual studio version is not matched with your one(VS2008 Express, Standart, Pro or Team System/ VS2010 Professional, Premium or Ultimate)

After search on net I have found several solution, now these solutions are share with you.

Solution 1:(this is worked for me)

Open the Project.csproj file with any editor like notepad or notepad++,
Delete whatever you found between <ProjectTypeGuids></ProjectTypeGuids>

Solution 2:

Open a new cmd prompt with admin privilege.
Type “devenv / setup” and then run(takes a while without any visual activity).

Solution 3:

Open a new cmd prompt with admin privilege.
Type “devenv /ResetSkipPkgs” and then run(takes a while without any visual activity).


Useful Tips
This tips is not this error specific. But hope that helpful for others. Sometimes we can't open our web project using solution. One of the main reason is that this web project is configured for IISUSER only. So to open this type of project:

1.Open the web.config file
2.Find the <IISUSER></IISUSER>
3. Make it False=> <IISUSER>False</IISUSER>
Now hopefully you web project is open by solution.

How to convert DataTable to generic List

I have discussed about conversion of DataTable to Generic List<t>. We can do it in various way. I want to share with you some of them....

Solution 1:
DataTable dt = CreateDataTable();
List<datarow> list = new List<datarow>();
foreach (DataRow dr in dt.Rows)
{
list.Add(dr);
}

Solution 2:
DataTable table = new DataTable {
Columns = {
{"Foo", typeof(int)},
{"Bar", typeof(string)}
}
};
for (int i = 0; i < 5000; i++) {
table.Rows.Add(i, "Row " + i);
}

List<T> data = new List<t>(table.Rows.Count);
foreach (DataRow row in table.Rows) {
data.Add(new T((int)row[0], (string)row[1]));
}

Solution 3:
Using Linq/lamda expression. It return data in List<t>.
List<string> list =dataTable.Rows.OfType<datarow>().Select(dr => dr.Field<string>(0)).ToList();

Solution 4:
Using Linq/lamda expression.
List<employee> list= new List<employee>();
list= (from DataRow row in dt.Rows
select new Employee
{
FirstName = row["ColumnName"].ToString(),
LastName = row["ColumnName"].ToString()

}).ToList();


Solution 5:
Using Linq/lamda expression.
List<t> target = dt.AsEnumerable()
.Select(row => new T
{
// assuming column 0's type is Nullable<long>
ID = row.Field<long?>(0).GetValueOrDefault()
Name = String.IsNullOrEmpty(row.Field<string>(1))
? "not found"
: row.Field<string>(1)
})
.ToList();


Solution 6:
Using Linq/lamda expression. All are return array of datarow in List<t>.

List<datarow> list1= dataTable.Select().ToList();
List<datarow> list2= dataTable.Rows.Cast<datarow>().ToList();
List<datarow> list3 = dataTable.AsEnumerable().ToList();
List<datarow> list4 = new List<datarow>(dataTable.select());

Here result will return all rows of datatable, as an array of datarows, and the List constructor accepts that array of objects as an argument to initially fill our List<datarow> with.

Solution 7:
Using reflection PropertyInfo class.

sealed class Tuple<T1, T2>
{
public Tuple() {}
public Tuple(T1 value1, T2 value2) {Value1 = value1; Value2 = value2;}
public T1 Value1 {get;set;}
public T2 Value2 {get;set;}
}


public static List<T> Convert<T>(DataTable table)
where T : class, new()
{
List<Tuple<DataColumn, PropertyInfo>> map =
new List<Tuple<DataColumn,PropertyInfo>>();

foreach(PropertyInfo pi in typeof(T).GetProperties())
{
ColumnAttribute col = (ColumnAttribute)
Attribute.GetCustomAttribute(pi, typeof(ColumnAttribute));
if(col == null) continue;
if(table.Columns.Contains(col.FieldName))
{
map.Add(new Tuple<DataColumn,PropertyInfo>(
table.Columns[col.FieldName], pi));
}
}

List<T> list = new List<T>(table.Rows.Count);
foreach(DataRow row in table.Rows)
{
if(row == null)
{
list.Add(null);
continue;
}
T item = new T();
foreach(Tuple<DataColumn,PropertyInfo> pair in map) {
object value = row[pair.Value1];
if(value is DBNull) value = null;
pair.Value2.SetValue(item, value, null);
}
list.Add(item);
}
return list;
}

Solution 8:
Another class using reflection PropertyInfo class.

public List<T> ConvertTo<T>(DataTable datatable) where T : new()
    {
        List<T> Temp = new List<T>();
        try
        {
            List<string> columnsNames = new List<string>();
            foreach (DataColumn DataColumn in datatable.Columns)
                columnsNames.Add(DataColumn.ColumnName);
            Temp = datatable.AsEnumerable().ToList().ConvertAll<T>(row => getObject<T>(row, columnsNames));
            return Temp;
        }
        catch
        {
            return Temp;
        }

    }
    public T getObject<T>(DataRow row, List<string> columnsName) where T : new()
    {
        T obj = new T();
        try
        {
            string columnname = "";
            string value = "";
            PropertyInfo[] Properties;
            Properties = typeof(T).GetProperties();
            foreach (PropertyInfo objProperty in Properties)
            {
                columnname = columnsName.Find(name => name.ToLower() == objProperty.Name.ToLower());
                if (!string.IsNullOrEmpty(columnname))
                {
                    value = row[columnname].ToString();
                    if (!string.IsNullOrEmpty(value))
                    {
                        if (Nullable.GetUnderlyingType(objProperty.PropertyType) != null)
                        {
                            value = row[columnname].ToString().Replace("$", "").Replace(",", "");
                            objProperty.SetValue(obj, Convert.ChangeType(value, Type.GetType(Nullable.GetUnderlyingType(objProperty.PropertyType).ToString())), null);
                        }
                        else
                        {
                            value = row[columnname].ToString().Replace("%", "");
                            objProperty.SetValue(obj, Convert.ChangeType(value, Type.GetType(objProperty.PropertyType.ToString())), null);
                        }
                    }
                }
            }
            return obj;
        }
        catch
        {
            return obj;
        }
    }


Hopefully it will help other developers.

How to remove duplicate row from a DataTable

Today in my development procedure I want to remove duplicate rows from DataTable. There is a lot of solution in community. But I think that I need to make the solution for flexibility of use.
Now I want to shared this with you. Hope that it will helpful for others developers.

First Solution:

public DataTable RemoveDuplicateRows(DataTable dTable, string colName)
{
Hashtable hTable = new Hashtable();
ArrayList duplicateList = new ArrayList();

//Add list of all the unique item value to hashtable, which stores combination of key, value pair.
//And add duplicate item value in arraylist.
foreach (DataRow drow in dTable.Rows)
{
if (hTable.Contains(colName==""?drow[0]:drow[colName]))
duplicateList.Add(drow);
else
hTable.Add(colName==""?drow[0]:drow[colName], string.Empty);
}

//Removing a list of duplicate items from datatable.
foreach (DataRow dRow in duplicateList)
dTable.Rows.Remove(dRow);

//Datatable which contains unique records will be return as output.
return dTable;
}

we can call this method

RemoveDuplicateRows(dataTable,""); or
RemoveDuplicateRows(dataTable,"word");

Second Solution:

private void btnRemove_Click(object sender, EventArgs e)
{
List keyColumns = new List();
keyColumns.Add("ColumnName1");
keyColumns.Add("ColumnName2");
keyColumns.Add("ColumnName3");
RemoveDuplicates(ref dtAlarmData, keyColumns);
}

//Method to remove Duplicate value from DataTable

public static void RemoveDuplicatesFromDataTable(ref DataTable table, List keyColumns)
{
Dictionary uniquenessDict = new Dictionary(table.Rows.Count);
StringBuilder stringBuilder = null;
int rowIndex = 0;
DataRow row;
DataRowCollection rows = table.Rows;
while (rowIndex < rows.Count - 1) { row = rows[rowIndex]; stringBuilder = new StringBuilder(); foreach (string colname in keyColumns) { //If no column name found it will check the first column by default. stringBuilder.Append(colname==""?((string)row[0]):((string)row[colname]));
}

if (uniquenessDict.ContainsKey(stringBuilder.ToString()))
{
rows.Remove(row);
}
else
{
uniquenessDict.Add(stringBuilder.ToString(), string.Empty);
rowIndex++;
}
}
}

Tuesday, February 7, 2012

Compare to List using C# and LINQ

LINQ offers developers a lot of useful features by which developers can solve more complex solution in a easy way. Today our discussion about comparison of two lists or collections.

Sample code 1:

static void Main(string[] args)
{
List strList1 = new List{"Jack","And","Jill","Went","Up","The","Hill"};
List strList2 = new List{"Jack", "And", "Jill", "Went", "Down", "The", "Hill"};

Console.WriteLine("Except result ...........");
var lstExcept = strList2.Except(strList1);
foreach (var variable in lstExcept)
{
Console.WriteLine(variable);
}

Console.WriteLine("Insect result ...........");
var lstInsect = strList2.Intersect(strList1);
foreach (var variable in lstInsect)
{
Console.WriteLine(variable );
}

Console.WriteLine("Union result ...........");
var lstUnion = strList2.Union(strList1);
foreach (var variable in lstUnion)
{
Console.WriteLine(variable );
}
Console.ReadLine();
}

Output:



Note that if you want to, say, ignore case:

List except = listA.Except(listB, StringComparer.OrdinalIgnoreCase);
You can replace the last parameter with an IEqualityComparer of your choosing.

You can get more information from here.

Sample code 2:
In sample code 1 just showing simple implementation. Now showing some more complex implementation.

This solution produces a result list, that contains all differences from both input lists. You can compare your objects by any property, in my example it is ID. The only restriction is that the lists should be of the same type:

var DifferencesList = ListA.Where(x => !ListB.Any(x1 => x1.id == x.id))
.Union(ListB.Where(x => !ListA.Any(x1 => x1.id == x.id)));

Using RequiredField Validator with CKEditor in ASP.Net

Last day I have faced a problem with CKEDITOR and asp.net required field validator. Strange problem! When I left blank the textarea(CKEDITOR) required field validate it properly. But when I filled up textarea still now required field validator showed error message for entering data.

After some r&d I have found that the requiredfield validator control will not work properly when it is used with a textarea that is configured with CKEditor. This is due to the fact that, the CKEditor content will not be synched to the page element(textarea) properly when the validator control fire.

To overcome this difficulty, we need to call the method .updateElement() in order to sync or post the content back to the textarea.

Solution:


<head>
<title>CKEDITOR TEST</title>
<script src="_scripts/jquery-1.3.2.min.js" type="text/javascript"></script>
<script type="text/javascript" src="ckeditor/ckeditor.js"></script>
<script type="text/javascript" src="ckeditor/adapters/jquery.js"></script>

<script type="text/javascript" language="javascript">

$(document).ready(function() {
var textBoxId = $(".test").attr('id');
if (!CKEDITOR.instances[textBoxId]) {
$('#textBoxId').ckeditor();
});


function UpdateContent() {
var textBoxId = $(".test").attr('id');
if (textBoxId != null) {
var editor = CKEDITOR.instances[textBoxId];
editor.updateElement();
}
}

</script>

</head>

<body>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="TextBox1" CssClass="test" MaxLength="3000" TextMode="MultiLine" Rows="3" runat="server"></asp:TextBox>

<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server"
ControlToValidate="TextBox1" ErrorMessage="No content in CKEditor!"></asp:RequiredFieldValidator>

</div>

<asp:Button ID="btnSave" OnClientClick="javascript:UpdateContent()" runat="server" Text="Save" onclick="btnSave_Click" />

<asp:Label ID="lblError" CssClass="error-msg" runat="server" Text=""></asp:Label>
</form>
</body>

Method 'StartWorkflowOnListItem' in type 'Microsoft.SharePoint.WorkflowServices.FabricWorkflowInstanceProvider'

Exception: Method 'StartWorkflowOnListItem' in type 'Microsoft.SharePoint.WorkflowServices.FabricWorkflowInstanceProvider'...