tags:

views:

189

answers:

5

Below is my code:

protected void SubmitCSV_Click(object sender, ImageClickEventArgs e)
    {   //Check Routes File Uploader for file
        if (ImportCSV.HasFile)
        {
            //Get File name
            string fileName = ImportCSV.FileName;
            //Read CSV
            StreamReader ReadUploadedFile = new StreamReader(ImportCSV.FileContent);
            //Parse CSV
            var pathOfCSVFile = ReadUploadedFile;
            //Gather CSV contents
            var adapter = new GenericParsing.GenericParserAdapter(pathOfCSVFile);
            //Ignore first row
            adapter.FirstRowHasHeader = true;

  DataTable TempRouteDataTable = adapter.GetDataTable();

if (ExcelDDL.SelectedValue == "Active Service Keys" && fileName == "ActiveServiceKeys.csv")
   {
    SEPTA_DS.ActiveServiceKeysTBLDataTable GetActiveServiceKeys = (SEPTA_DS.ActiveServiceKeysTBLDataTable)askta.GetData();
    var hasData = GetActiveServiceKeys.Rows.Count > 0;

    //Loop through each row and insert into database
    foreach (DataRow row in TempRouteDataTable.Rows)
            {
              //Gather column headers
              var category = Convert.ToString(CategoryDDL.SelectedItem);
              var agency = Convert.ToString(row["Agency"]);
              var route = Convert.ToString(row["Route"]);
              var direction = Convert.ToString(row["Direction"]);
              var serviceKey = Convert.ToString(row["Service Key"]);
              var language = Convert.ToString(row["Language"]);
              var activeServiceKeys = Convert.ToString(row["Active Service Keys"]);

              //Check if data already exists
              if (hasData == true)
               {
               var originalID = Convert.ToInt32(GetActiveServiceKeys.Rows[0] ["ActiveServiceKeysID"]);
               int updateData = Convert.ToInt32(askta.UpdateActiveServiceKeys(category, agency, route, direction, serviceKey, language, activeServiceKeys, originalID));
               }
               else
               {
                int insertData = Convert.ToInt32(askta.InsertActiveServiceKeys(category, agency, route, direction, serviceKey, language, activeServiceKeys));
               }
             }
          }
     }
}

The problem arises after rows exist. The foreach is currently reading a CSV uploaded so eahc time the foreach is fired it places a row into the database.

EDIT:

When data DOES NOT exist in the database I want to run the insert method. When it DOES exist I want to run the update method.

PROBLEM: When running an update method you require the originalID (auto-incrementing int). Since each row from the uploading CSV is within a foreach I am unfamiliar on how to grab the originalID per loop.

Currently, (just fixed) I had a 0 but that will not change per loop.

A: 

What is GetActiveServiceKeys? Shouldnt you be trying to pull that ID from the row[] context?

AlvinfromDiaspar
+1  A: 

I share the confusion of others, but here's one observation: It's probably not a good idea to base the Update vs Insert logic on the fact that there is some existing data. What if the CSV contains one new row and one row to update? What if the existing data doesn't overlap at all with the data in the CSV?

You probably want there to be logic like Alvin mentioned, which pulls the ID from the row. After that, check if the ID exists in the database already and use the result to determine whether it's an insert or update.

Rob H
+1  A: 

Consider refactoring your code to use LINQ, and an object oriented solution. It'll make it much easier to read & maintain!

Create a class to mirror your datatable's row. Here I've called it MyDTO

foreach ( var item in dt.Rows.Cast<DataRow>().Select(r=> new MyDTO {                 
          category =  CategoryDDL.SelectedItem.ToString(),
          agency =    r["Agency"].ToString(),
          route =     r["Route"].ToString(),
          direction = r["Direction"].ToString(),
          serviceKey= r["Service Key"].ToString(),
          language =  r["Language"].ToString(),
          originalID = GetActiveServiceKeys.Rows[r["Active Service Keys"].ToString()]
          activeServiceKeys =  r["Active Service Keys"].ToString()}
        ))
      {
       if (!string.IsNullOrEmpty(item.originalID))            
           int updateData = askta.UpdateActiveServiceKeys(item);
        else
           int insertData = askta.InsertActiveServiceKeys(item);
      }

This requires that you change the interface to askta methods InsertActiveServiceKeys and UpdateActiveServiceKeys() to take a param of type MyDTO instead of a long list of value data types. Easier to maintain!

Note that MyDTO has OriginalID as a property, and the check for whether it exists is built right into the Select.

Here's a sample on PasteBin. Ensure that you're using System.Linq;.

p.campbell
Bry4n
@Bry4n: you bet; just need to make yourself that new class MyDTO. Also ensure your 2 `askta` methods actually return an integer. You'll have to ensure the `GetActiveServiceKeys.Rows` bit is correct.
p.campbell
@p.campbell `dt` needs to be changed to `TempRouteDataTable` doesn't it?
Bry4n
@p.campbell I am getting an error on the `originalID` it says it requires an `int` within the `foreach`.
Bry4n
@Bry4n: right, `dt` was my local code in testing. re: `originalID`... make sure that it's defined as a string in your DTO, and that `GetActiveServiceKeys.Rows` returns a string. See my updated pastebin link.
p.campbell
@p.campbell I had the newer version already. Both are set to strings. This is what i see when hovering over the error - `DataRow DataRowCollection[int index]` and has invalid arguments.
Bry4n
@Bry4n: ah, of course. Rows takes an index. try `GetActiveServiceKeys.Rows[int.Parse(r["Active Service Keys"].ToString())].ToString()`
p.campbell
@p.campbell We are making progress. There are no more development errors however there is one on runtime. I get this error `Input string was not in a correct format.` when submitting. I think the issue might be because the ActiveServiceKeyID is the primary key in the datatable hence my confusion when you wanted that to become a string.
Bry4n
@Bry4n: right. perhaps use `int.Parse()` on that property when necessary closer to the database level, or redefine it as an int in your DTO + cast in your query. This this happening in the `UpdateActiveServiceKeys` ?
p.campbell
@p.campbell I change it within my class and in the statement like so `activeServiceKeysID = Convert.ToInt32(GetActiveServiceKeys.Rows[Convert.ToInt32(r["Active Service Keys"])]),` which erased all ugly red-line errors. However the same error persists and seems to be highlighting `foreach ( var item in TempRouteDataTable.Rows.Cast<DataRow>().Select(r=> new ActiveServiceKeysPC {` for the most part.
Bry4n
@p.campbell I found the erro but discovered a second..sigh. The reason it was erroring because you can't insert the primary key (ActiveServiceKeysID) because it auto-increments. At least this is what I think. Also having removed the ID as a test and trying to insert, I got all the way to the inset statement and hit this error `No mapping exists from object type Import+ActiveServiceKeysPC to a known managed provider native type.` We just can't win =/
Bry4n
@Bry4n: sounds like a SQL Server error. Consider capturing the SQL statement as it crosses from your app to your DB. Use SQL Profiler if you're using SQL Server.
p.campbell
@p.campbell The main issue still stands. Even if I fixed the SQL error I can't `insert` the primary key due to auto-incrementing. Right?
Bry4n
@Bry4n: right, you can't typically insert an auto-incrementing PK, but you can temporarily turn it off by sending `SET IDENTITY_INSERT MyTable ON`. That assumes that there isn't another row with that PK on it.
p.campbell
A: 

This line var originalID = Convert.ToInt32(GetActiveServiceKeys.Rows[ ["ActiveServiceKeysID"]); does not really make sense. I infer from it that what you're trying to do is match up the row of the current iteration of your foreach loop with a particular row in your GetActiveServiceKeys table and then obtain the value of the ActiveServiceKeysID column so that you can use it for your update statement.

Here are some points to consider:

  1. You need a way to find the appropriate row in the GetActiveServiceKeys table given the values of the current row from the uploaded file. Ideally, you'd have some kind of unique key specified within the uploaded file. Is there no such key? I'm assuming there is no ActiveServiceKeysID value within the uploaded file, otherwise you could just use that directly without looking it up from the other table. Is there any other set of fields that can be used to uniquely identify a row? If not, then performing a simple update on a single row is probably going to be impossible.

  2. Can the uploaded file have a mixture of existing rows to update as well as new rows to insert? In your current code, you basically decide whether you are in "insert" mode or "update" mode based on whether there are already rows in your database. I'd prefer to handle each row individually and do a check to see whether or not the GetActiveServiceKeys table contains a row matching that row.

  3. Another alternative is to simply purge your current database's ActiveServiceKeys table and replace it with the content of the uploaded file.

Dr. Wily's Apprentice
A: 

I worked with p.campbell to uss LINQ but I was running into too many errors although I am sure if I had more time I could have gotten it to work.

I used this method and it seemed to work. It checks to see if the item exists, if so it updates if not it adds it.

//Loop through each row and insert into database
                int i = 0;
                foreach (DataRow row in TempRouteDataTable.Rows)
                {
                    //Gather column headers
                    var category = Convert.ToString(CategoryDDL.SelectedItem);
                    var agency = Convert.ToString(row["Agency"]);
                    var route = Convert.ToString(row["Route"]);
                    var direction = Convert.ToString(row["Direction"]);
                    var serviceKey = Convert.ToString(row["Service Key"]);
                    var language = Convert.ToString(row["Language"]);
                    var activeServiceKeys = Convert.ToString(row["Active Service Keys"]);
                    var origID = -1;

                    if (GetActiveServiceKeys.Rows.Count > 0)
                    {
                        origID = Convert.ToInt32(GetActiveServiceKeys.Rows[i]["ActiveServiceKeysID"]);
                        var GetID = (SEPTA_DS.ActiveServiceKeysTBLDataTable)askta.GetDataByID(origID);
                        if (GetID.Rows.Count < 1)
                        {
                            origID = -1;
                        }
                    }

                    if (origID == -1)
                    {
                        int insertData = Convert.ToInt32(askta.InsertActiveServiceKeys(category, agency, route, direction, serviceKey, language, activeServiceKeys));
                    }
                    else
                    {
                        int updateData = Convert.ToInt32(askta.UpdateActiveServiceKeys(category, agency, route, direction, serviceKey, language, activeServiceKeys, origID));
                    }
                    i++;
                 }
Bry4n