Saturday, August 06, 2011

AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges.

AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges.

I got this error while working with WCF, Entity Framework 4.0 and C#.Net 2010, I had one object bind with parent child relationship and when I tried to delete record from child object first and then from parent object, that time I got this error. 
Basically when you have relational entity object and want to execute all delete operation in single transaction, then you have to attach the object into the context and then remove it, instead of doing ApplyChanges(), this method will maintain the object key’s into ObjectStateManager and when you try to remove data from parent object then It will throw this error. I spend enough time to find the solution of this error.

Let’s say you have object structure like below

public class Country
{
   //Default Constructor
   public Country() { CountryState = new List<States>(); }
   public string Name { get; set; }
   public int Id { get; set; }
   public List<States> CountryState { get; set; }
} 
public class States
{
   public string Name { get; set; }
   public int Id { get; set; }       
}

All data I have in “countryObject”

//Load this object with actual data
List<Country> countryObject = new List<Country>();

Now the code I got this error is below

using (var ctx = DataBaseContext)
{
   using (var tc = new TransactionScope())
   {
      foreach (Country con in countryObject)
       {
         foreach (States sat in con.CountryState)
         {
            //Delete Data from CHIILD Table/Object
            sat.MarkAsDeleted();
            ctx.States.ApplyChanges(sat);
         } 

         //Delete Data from PARENT Table/Object
         con.MarkAsDeleted();
         ctx.Country.ApplyChanges(con); //ERROR                    
        } 
        //Save the Changes
        ctx.SaveChanges(); 
        //Commit the transaction
        tc.Complete();
      }
 }

The code I resolved this error

using (var ctx = ServiceUtility.Context)
{
   using (var tc = new TransactionScope())
   {
       foreach (Country con in countryObject)
       {
         foreach (States sat in con.CountryState)
         {
           //Delete Data from CHIILD Table/Object
           sat.MarkAsDeleted();
           ctx.States.Attach(sat);
           ctx.States.DeleteObject(sat);
         } 
         
//Delete Data from PARENT Table/Object
       con.MarkAsDeleted();
       ctx.Country.Attach(con);
       ctx.Country.DeleteObject(con);
      } 
    //Save the Changes
    ctx.SaveChanges();
    //Commit the transaction
    tc.Complete();
  }
}


Note: if you use ctx.SaveChanges(); in a loop or after every Deleteobject() method then you might get following error
"Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries." 

Thursday, August 04, 2011

How to add two same type of List<> Objects into third same type of List<> Object in C#.NET


How to add two same type of List<> Objects into third same type of List<> Object in C#.NET  
  
For adding multiple objects into some other object, it’s common requirement, Let’s see below the example for this

List<Country> Con1 = new List<Country>(); 
List<Country> Con2 = new List<Country>(); 
List<Country> Con3 = new List<Country>();

Let say you have Con1 and Con2, your requirement to Add these two objects into Con3

Way -1

Con3 = AddCountryList(Con3, Con1); 
Con3 = AddCountryList(Con3, Con2);

private List<Country> AddCountryList(List<Country> finalObject, List<country> sourceObject)
{
    foreach (Country ctn in sourceObject)
     {
         finalObject.Add(ctn);
     }
  return finalObject;
}

Way -2

You can use List<> object method called “AddRange” to achieve this

Con3.AddRange(Con1);
Con3.AddRange(Con2);

Tuesday, August 02, 2011


How to Query Objects inside Objects using LINQ

Using LINQ you can avoid for each loop completely by using LINQ query, LINQ is much faster than Loop. I am giving one example below to clarity this

Assume you have some Object structure like below, One object has reference to others

    public class Country
    {
        public string Name { get; set; }
        public int Id { get; set; }
        public List<States> State { get; set; }
    } 
    public class States
    {
        public string Name { get; set; }
        public int Id { get; set; }
        public List<City> City { get; set; }
    } 
    public class City
    {
        public string Name { get; set; }
        public int Id { get; set; }
        public List<Area> Area { get; set; }
    } 
    public class Area
    {
        public string Name { get; set; }
        public int Id { get; set; }
    }
  
You have some data in it and which will in the form of parent child relationship

Ex:

-India  
---MP
----Jabalpur
------Street no 300

Like this you have 1000 of Country data. And your requirement to update the Area of each country  

You have loaded data in following Object and declared globally to use

List<Country> _country = new List<Country>();

To achieve this one way is to loop through till child most and update the data like below

One Way

foreach (Country cn in _country)
{
   foreach (States st in cn.State)
   {
      foreach (City ct in st.City)
       {
         foreach (Area ar in ct.Area)
          {
            if (ar.Id == id)
             {
               Ar.Name = “Updated Name here”;
             }
           }
        }
     }
 }

Second Way

Now look into other way of doing the same using LINQ to Object

 (from ctn in _country
     from st in ctn.State
       from ct in st.City
         from ar in ct.Area
           select ar).Where(s => s.Id == id)
             .ToList<Service>().ForEach(a => 
                      { a.Name = “Updated Name here”});

Conclusion: LINQ query is much more efficient to do this kinds of work and using this you can gain 90% fast performance avoiding Loops inside Loops.

Thursday, July 07, 2011

How to set browser language as a default language for .NET Silverlight application

How to set browser language as a default language for .NET Silverlight application
Here the requirement is that, the application should change its culture based on the Browser language setting. Let say if user changed his language in IE browser then application should reflect with same culture.  Ex: US English (default) to French (standard)
In short, the application should display the content based on client browser settings.
Steps-1: Read Browser Language from code
You have to write inline code into Default.aspx page (Page_Init())
Namespace
<%@ Import Namespace="System.Globalization" %>
<%@ Import Namespace="System.Threading" %>
C# code
<script runat="server">
void Page_Init(object sender, EventArgs e)
{
  ViewStateUserKey = Session.SessionID;
  if (HttpContext.Current.Request.UserLanguages != null)
  {
    CultureInfo culture = new CultureInfo(HttpContext.Current.Request.UserLanguages[0]);
    Thread.CurrentThread.CurrentCulture = culture;
    Thread.CurrentThread.CurrentUICulture = culture;
  }
 }
</script>

Steps-2: Go to the Main Page and set language
 
Set application language with current culture on the page Constructor after InitializeComponent() method
 
this.Language = System.Windows.Markup.XmlLanguage.GetLanguage(System.Threading.Thread.CurrentThread.CurrentCulture.Name);

Steps-3: Create Resource files for different languages
Resource file name should create with following manner
<ResounceFileName>.<Language ISO Code>.resx
Ex:
French (Canada)   file name should be "Resource.fr-FR.resx"
Dutch file name should be "Resource.nl.resx"
Run the application and now application will behave based on the language set into the browser.
This code has been tested with IE 9.0 32 bit browser and Silverlight 4.0 with .NET framework 4.0.
Note: following solution you can try with asp.NET application, steps 1 and 3 will be same

Friday, June 17, 2011

How to convert date time format based on the languages in C#.NET


How to convert date time format based on the languages in C#.NET

If you want to convert date into different languages date, you can use .NET globalization library for this purpose, see the example below

Namespace

using System.Globalization;

Source Code

//Type the ISO code based on languages you want like English: en-us, Genman: de, French (Canada): fr-ca 
CultureInfo culInfo = new CultureInfo(textBox1.Text);
//I am converting current date into desired language datetime format
DateTime dtUs = Convert.ToDateTime(DateTime.Now, culInfo.DateTimeFormat);
//this will give Typed language date format
label1.Content = string.Format("{0} {1}",culInfo.DateTimeFormat.ShortDatePattern,culInfo.DateTimeFormat.LongTimePattern);
//this will give Typed language date and time
label2.Content = dtUs.ToString(culInfo.DateTimeFormat.ShortDatePattern + " " + culInfo.DateTimeFormat.LongTimePattern);

Check code like

textBox1.Text  = “fr-ca”  // for Canada (French)

How to Read/Write Data from DBF file using C#.net application.

How to Read/Write Data from DBF file using C#.net application.

Overview:

This document is useful to create import export utility for DBF file. Some time it does require import/export data from DBF file from your DOTNET application. Currently I am working on same kind of requirement where I have developed Export Import Utility it's include export/import data from various file type. One of toughest type is DBF file import export, I did some research on that and got one reboots solution that I want to share with you all.

This document covers the following

1) How to create DBF file database table
2) How to Insert data in created DBF file
3) How to Read data from DBF file.

Introduction:

DBF is a FoxPro database file, this we can create from C#.net application even we can use basic DDL and DML statement on this like 'Create table' , 'Insert table' etc.
If our requirement is to export your data which in is the Dataset (in C#.net) in DBF file this document will help you. You can also read data from any DBF file using this document. Using the same function with different connection string you can use to read / write excel file too.

How function works.

1) I have created one function for Export DBF file; this will takes one dataset as an input parameter
2) Based on input dataset parameter I am creating the database table using 'create table' statement.
3) Then I open the connection using 'Microsoft.Jet.OLEDB.4.0' provider.
4) Using OleDbDataAdapter object I am filling the dataset (dsFill) this will create one DBF table structure with given table name.
5) Now using the Same connection you can fire the next DML statement 'Insert into ..' to insert the data into the DBF file.
6) And same way you can read the data using 'Select..' statement. Fro Import.

Some points are important here

1) DBF file creates with Table name (TEMP.dbf) given in the 'Create table TEMP...' statement.
2) If you are reading the DBF file using 'Select ...' statement the select statement should be like 'Select * from TEMP'.
3) Key words are not acceptable in the DDL or DML statement. Like table, date etc.
4) This will take data source as folder name where DBF file exist like If you want to export / Import DBF file from "C:\Temp\country.dbf." then your Data source will be "C:\Temp" and Table name will be "country".

Source Code:

Follow the simple steps to create application. You can simply copy and past code from here in your application

1) Create the function which will give you the folder path and table name

private void GetFileNameAndPath(string completePath, ref string fileName, ref string folderPath)
{
string[] fileSep = completePath.Split('\\');
for (int iCount = 0; iCount < fileSep.Length; iCount++)
{
if (iCount == fileSep.Length - 2)
{
if (fileSep.Length == 2)
{
folderPath += fileSep[iCount] + "\\";
}
else
{
folderPath += fileSep[iCount];
}
}
else
{
if (fileSep[iCount].IndexOf(".") > 0)
{
fileName = fileSep[iCount];
fileName = fileName.Substring(0, fileName.IndexOf("."));
}
else
{
folderPath += fileSep[iCount] + "\\";
}
}
}
}
Note: Use the folderPath and DataSource in the connection string and fileName in the 'Create tabel' statement.

1) Create ExportDBF function.

// This function takes Dataset (to be exported) and filePath as input parameter and return // bool status as output parameter
// comments are written inside the function to describe the functionality
public bool EportDBF(DataSet dsExport, string filePath)
{
string tableName = string.Empty;
string folderPath = string.Empty;
bool returnStatus = false;
// This function give the Folder name and table name to use in
// the connection string and create table statement.
GetFileNameAndPath(filePath, ref tableName, ref folderPath);
// here you can use DBASE IV also
string connString = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" + folderPath + "; Extended Properties=DBASE III;";
string createStatement = "Create Table " + tableName + " ( ";
string insertStatement = "Insert Into " + tableName + " Values ( ";
string insertTemp = string.Empty;
OleDbCommand cmd = new OleDbCommand();
OleDbConnection conn = new OleDbConnection(connString);
if (dsExport.Tables[0].Columns.Count <= 0) { throw new Exception(); }
// This for loop to create "Create table statement" for DBF
// Here I am creating varchar(250) datatype for all column.
// for formatting If you don't have to format data before
// export then you can make a clone of dsExport data and transfer // data in to that no need to add datatable, datarow and
// datacolumn in the code.
for (int iCol = 0; iCol < dsExport.Tables[0].Columns.Count; iCol++)
{
createStatement += dsExport.Tables[0].Columns[iCol].ColumnName.ToString();
if (iCol == dsExport.Tables[0].Columns.Count - 1)
{
createStatement += " varchar(250) )";
}
else
{
createStatement += " varchar(250), ";
}
}
//Create Temp Dateset
DataSet dsCreateTable = new DataSet();
//Open the connection
conn.Open();
//Create the DBF table
DataSet dsFill = new DataSet();
OleDbDataAdapter daInsertTable = new OleDbDataAdapter(createStatement, conn);
daInsertTable.Fill(dsFill);
//Adding One DataTable into the dsCreatedTable dataset
DataTable dt = new DataTable();
dsCreateTable.Tables.Add(dt);
for (int row = 0; row < dsExport.Tables[0].Rows.Count; row++)
{
insertTemp = insertStatement;
//Adding Rows to the dsCreatedTable dataset
DataRow dr = dsCreateTable.Tables[0].NewRow();
dsCreateTable.Tables[0].Rows.Add(dr);
for (int col = 0; col < dsExport.Tables[0].Columns.Count; col++)
{
if (row == 0)
{
//Adding Columns to the dsCreatedTable dataset
DataColumn dc = new DataColumn();
dsCreateTable.Tables[0].Columns.Add(dc);
}
// Remove Special character if any like dot,semicolon,colon,comma // etc
dsExport.Tables[0].Rows[row][col].ToString().Replace("LF", "");
// do the formating if you want like modify the Date symbol , //thousand saperator etc.
dsCreateTable.Tables[0].Rows[row][col] = dsExport.Tables[0].Rows[row][col].ToString().Trim();
} // inner for loop close
// Create Insert Statement
if (col == dsExport.Tables[0].Columns.Count - 1)
{
insertTemp += "'" + dsCreateTable.Tables[0].Rows[row][col] + "' ) ;";
}
else
{
insertTemp += "'" + dsCreateTable.Tables[0].Rows[row][col] + "' , ";
}
// This lines of code insert Row One by one to above created
// datatable.
daInsertTable = new OleDbDataAdapter(insertTemp, conn);
daInsertTable.Fill(dsFill);
} // close outer for loop
MessageBox.Show("Exported done Successfully to DBF File.");
returnStatus = true;
} // close function
Note: for formatting like date and thousand separators add below lines of code while transfer data from one dataset to another.
1) Char decimalSymbol = '/'; /. Or "."
dsCreateTable.Tables[0].Rows[row][col] = Convert.ToString(Convert.ToDecimal(dsExport.Tables[0].Rows[row][col].ToString().Trim())).Replace('.', decimalSymbol);
2) string thousandSeparator = "#" + "" + "###"; // or ","
dsCreateTable.Tables[0].Rows[row][col] = Convert.ToString(Convert.ToDouble(dsExport.Tables[0].Rows[row][col].ToString().Trim()).ToString(thousandSeparator));
3) string dateFormat ="MM/dd/yyyy";
dsCreateTable.Tables[0].Rows[row][col] = Convert.ToString(Convert.ToDateTime(dsExport.Tables[0].Rows[row][col].ToString().Trim()).ToString(dateFormat));

2) Create ImportDBF function.

// This function takes filePath as input parameter and return DataSet as output parameter
// comments are written inside the function to describe the functionality
public DataSet ImportDBF(string filePath)
{
string ImportDirPath = string.Empty;
string tableName = string.Empty;
// This function give the Folder name and table name to use in
// the connection string and create table statement.
GetFileNameAndPath(filePath, ref tableName, ref ImportDirPath);
DataSet dsImport = new DataSet();
string thousandSep = thousandSeparator;
string connString = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" + ImportDirPath + "; Extended Properties=DBASE IV;";
OleDbConnection conn = new OleDbConnection(connString);
DataSet dsGetData = new DataSet();
OleDbDataAdapter daGetTableData = new OleDbDataAdapter("Select * from " + tableName , conn);
// fill all the data in to dataset
daGetTableData.Fill(dsGetData);
DataTable dt = new DataTable(dsGetData.Tables[0].TableName.ToString());
dsImport.Tables.Add(dt);
// here I am copying get Dataset into another dataset because //before return the dataset I want to format the data like change //"datesymbol","thousand symbol" and date format as did while
// exporting. If you do not want to format the data then you can // directly return the dsGetData
for (int row = 0; row < dsGetData.Tables[0].Rows.Count; row++)
{
DataRow dr = dsImport.Tables[0].NewRow();
dsImport.Tables[0].Rows.Add(dr);
for (int col = 0; col < dsGetData.Tables[0].Columns.Count; col++)
{
if (row == 0)
{
DataColumn dc = new DataColumn(dsGetData.Tables[0].Columns[col].ColumnName.ToString());
dsImport.Tables[0].Columns.Add(dc);
}
if (!String.IsNullOrEmpty(dsGetData.Tables[0].Rows[row][col].
ToString()))
{
dsImport.Tables[0].Rows[row][col] = Convert.ToString(dsGetData.Tables[0].Rows[row][col].ToString().Trim());
}
} // close inner for loop
}// close ouer for loop
MessageBox.Show("Import done Successfully to DBF File.");
Return dsImport;
} // close function
Note: Same function you can use to Export Import from Excel file also
Use
string connString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + filePath + ";Extended Properties=Excel 8.0";
// filePath = complete path like "C:\Temp\country.xls"

Import Excel

string strconn = "Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data Source=" + filePath + ";Extended Properties=Excel 8.0";
OleDbDataAdapter da = new OleDbDataAdapter("select * from [" + fileName + "$]", strconn);
DataSet dsExcel = new DataSet();
da.Fill(dsExcel);

Export Excel

Same as Export DBF file with different connection string.
string connString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + filePath + ";Extended Properties=Excel 8.0";
// filePath = complete path like "C:\Temp\country.xls"

Windows Requirements
Windows 2000, XP and above
Language
C#.NET and ASP.NET, Visual Studio 2003 and above