Search code examples
c#winformsentity-frameworkoledbdbf

EntityFramework doesn't SaveChanges when importing data from .DBF file


I am trying to import Table from .DBF file into MSSQL database... My code works fine for 400 rows but if there is more than that, SaveChanges doesn't update database at all.

What my codes does:

Opens OleDb connection, reads data into DataTable via SelectCommand then I start "for loop" which places rows into Entity model objects

when the loop is done I SaveChanges - but it doesn't affect MSSQL db

Visual Studio shows no errors or exceptions?! It works fine with .DBF files that have under 400 rows but I have a file with 1200 rows which I want to save to DB pls help!

DataTable dt = new DataTable();
try
{
    // define the connections to the .dbf file
    OleDbConnection connection = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" + Path + ";Extended Properties=dBase III");
    OleDbCommand command = new OleDbCommand("SELECT sif_komin, naziv, oib, mjesto, adresa, telefon, telefax, mobitel, kontakt from KUPCI.dbf", connection);

    //open the connection and read in all the data from .dbf file into a datatable

    connection.Open();

    dt.Load(command.ExecuteReader());

    connection.Close();
}
catch(OleDbException)
{
    //handle exception
}

using (Entities db = new Entities()) //Entity object
{
    try
    {
        db.Komitents.RemoveRange(db.Komitents);

        for (int i = 0; i < 400; i++)
        {
            DataRow row = dt.Rows[i];
            if (row["naziv"].ToString() != "")// skips header row
            {
                Komitent k = new Komitent();
                k.Sif_komit = Convert.ToInt32(row["sif_komin"].ToString());
                k.Naziv = row["naziv"].ToString();
                k.Oib = row["oib"].ToString();
                k.Mjesto = row["mjesto"].ToString();
                k.Adresa = row["adresa"].ToString();
                k.Telefon = row["telefon"].ToString();
                k.Telefax = row["telefax"].ToString();
                k.Mobitel = row["mobitel"].ToString();
                k.Kontakt = row["kontakt"].ToString();

                db.Komitents.Add(k);
                bw.ReportProgress((int)(100.0 / dt.Rows.Count) * i, null);

                if (pb.InvokeRequired)
                {
                    this.Invoke((MethodInvoker)delegate
                    {
                        pb.Value = (int)((100.0 / dt.Rows.Count) * i);
                    });

                }
            }
        }

        db.SaveChanges();

Solution

  • I doubt this issue is really related with Entity Framework. It should doesn't make any difference to save 400 items or even 100,000 items!

    I have updated your code a little bit

    Check what's really happening in the AddRange, do the list contains really 1200 items or 0 item?

       using (Entities db = new Entities()) //Entity object
        {
            try
            {
                db.Komitents.RemoveRange(db.Komitents);
                // Jonathan: Let make 2 SaveChanges call for now to understand what's happening
                db.SaveChanges();
    
                // Jonathan: Create a list to use AddRange to improve performance
                List<Komitent> list = new List<Komitent>();
    
                for (int i = 0; i < 400; i++)
                {
                    DataRow row = dt.Rows[i];
                    if (row["naziv"].ToString() != "")// skips header row
                    {
                        Komitent k = new Komitent();
                        k.Sif_komit = Convert.ToInt32(row["sif_komin"].ToString());
                        k.Naziv = row["naziv"].ToString();
                        k.Oib = row["oib"].ToString();
                        k.Mjesto = row["mjesto"].ToString();
                        k.Adresa = row["adresa"].ToString();
                        k.Telefon = row["telefon"].ToString();
                        k.Telefax = row["telefax"].ToString();
                        k.Mobitel = row["mobitel"].ToString();
                        k.Kontakt = row["kontakt"].ToString();
    
                        list.Add(k);
                        bw.ReportProgress((int)(100.0 / dt.Rows.Count) * i, null);
    
                        if (pb.InvokeRequired)
                        {
                            this.Invoke((MethodInvoker)delegate
                            {
                                pb.Value = (int)((100.0 / dt.Rows.Count) * i);
                            });
    
                        }
                    }
                }
    
                // Jonathan: Put a break point here to make sure the list contains 1200 rows
                db.AddRange(list);
    
                db.SaveChanges();
            }
            catch
            {
                // Jonathan: Let throw the error for now until it fixed
                throw;
            }
        }
    

    Edit: Adding info to understand what's happening

    Tip 1: Use SQL Profiler to see if insert command are at least send to SQL Server or not at all.

    Tip 2: Try finding a row with a potential error, try adding 500, 550, 552 etc... until you find the right number of rows starting to cause the issue. Look at the last row to see if everything is fine or replace it with custom value.

    Tip 3: Make sure to have a break point in both catch in case the function caller also use a try/catch and doesn't handle the error.