LINQ上传CSV文件的实体,其中单行可以在列中具有多个值

时间:2014-08-08 13:48:57

标签: c# linq csv entity

我目前正在解析由另一个应用程序导出的csv文件。此应用程序以奇怪的方式导出数据。此出口来自accoutning,它看起来与此相似..

enter image description here

我正在试图找出一种方法来读取csv文件,然后拆分多个“所有帐户”值和“Amt”值,以便M200和300.89是另一个条目,M300和400.54是另一个条目,并且M400和100.00是另一个条目。因此,在将这一行插入数据库之后,我实际上应该有4行,如此...

enter image description here

这就是我目前正在阅读和插入数据库的方式。

List<RawData> data = new List<RawData>();

try
{
   string text = File.ReadAllText(lblFileName.Text);
   string[] lines = text.Split('\n');
   int total = 0, reduced = 0;
   foreach (string line in lines)
   {
      RawData temp = new RawData(line);
      total++;
      if (!(temp.FirstAccount.Length == 0 || temp.FirstAccount == "1ST-ACCT-NO"))
      {
         reduced++;
         data.Add(temp);
       }
    }
 }
 catch (IOException ex)
 {
     Console.WriteLine("Unable to read file. " + ex.ToString());
     MessageBox.Show(ex.ToString());
  }

  try
  {
     foreach (RawData rData in data)
     {
         tCarsInTransit cit = new tCarsInTransit
         {
             FIRST_ACCT_NO = rData.FirstAccount,
             ACCOUNT_NO_DV = rData.AccountNoDv,
             ACCT_NO = rData.AcctNo,
             ACCT_NO_L = rData.AccNoL,
             ACCT_NUM_DV = rData.AcctNumDv,
             ACCT_PFX = rData.AcctPfx,
             ACCT_PFX_PRT = rData.AcctPfxPrt,
             ACCT_TYPE_DV = rData.AcctTypeDv,
             ADV_NO = rData.AdvNo,
             ALL_PRT_FLAG = rData.AllPrtFlag,
             AMT = rData.Amt,
             AMT_GLE = rData.AmtGle,
             BASE_GLE = rData.BaseGle,
             CNT_CAT = rData.CntCat,
             COLD_PRT_FLAG = rData.ColdPrtFlag,
             COST_DV = rData.CostDv,
             COST_OVRD_FLAG_DV = rData.CostOvrdFlagDv,
             CR_ACCT_DV = rData.CrAcctDv,
             CR_ACCT_DV_GLE = rData.CrAcctDvGle,
             CROSS_POSTING_FLAG = rData.CrossPostingFlag,
             CROSS_POST_CAT = rData.CrossPostCat,
             CTRL_NO = rData.CtrlNo,
             CTRL_TYPE_DV = rData.CtrlTypeDv,
             DESC_REQD_DV = rData.DescReqdDv,
             DR_ACCT_DV = rData.DrAcctDv,
             GL_DIST_ACCT_DV = rData.GLDistAcctDv,
             GL_DIST_DV = rData.GLDistDv,
             GRP_NO_DV = rData.GrpNoDv,
             ID_PORT_DATE_TIME_FMT_CAT = rData.IdPortDateTimeFmtCat,
             INACTIVITY_DV = rData.InactivityDv,
             JOIN_COL = rData.JoinCol,
             JRNL_DATE = rData.JrnlDate,
             JRNL_PFX = rData.JrnlPfx
          };

          tCIT.tCarsInTransits.Add(cit);

          tCIT.SaveChanges();

          lblMessage.ForeColor = System.Drawing.Color.Green;
          lblMessage.Text = "Finished uploading. ";
       }
    }
    catch (DbEntityValidationException ex)
    {
       foreach (var eve in ex.EntityValidationErrors)
       {
          Console.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
             eve.Entry.Entity.GetType().Name, eve.Entry.State);
          foreach (var ve in eve.ValidationErrors)
          {
             Console.WriteLine("- Property: \"{0}\", Error: \"{1}\"",
                 ve.PropertyName, ve.ErrorMessage);
          }
        }
        throw;
     }

我不知道如何做到这一点。以上内容当前将csv文件以与csv文件导出的完全相同的方式插入到Sql Server中。任何想法将不胜感激!谢谢!

编辑:这是RawData类。

class RawData
{
    public string FirstAccount { get; set; }
    public string AccountNoDv { get; set; }
    public string AcctNo { get; set; }
    public string AccNoL { get; set; }
    public string AcctNumDv { get; set; }
    public string AcctPfx { get; set; }
    public string AcctPfxPrt { get; set; }
    public string AcctTypeDv { get; set; }
    public string AdvNo { get; set; }
    public string AllPrtFlag { get; set; }
    public string Amt { get; set; }
    public string AmtGle { get; set; }
    public string BaseGle { get; set; }
    public string CntCat { get; set; }
    public string ColdPrtFlag { get; set; }
    public string CostDv { get; set; }
    public string CostOvrdFlagDv { get; set; }
    public string CrAcctDv { get; set; }
    public string CrAcctDvGle { get; set; }
    public string CrossPostingFlag { get; set; }
    public string CrossPostCat { get; set; }
    public string CtrlNo { get; set; }
    public string CtrlTypeDv { get; set; }
    public string DescReqdDv { get; set; }
    public string DrAcctDv { get; set; }
    public string GLDistAcctDv { get; set; }
    public string GLDistDv { get; set; }
    public string GrpNoDv { get; set; }
    public string IdPortDateTimeFmtCat { get; set; }
    public string InactivityDv { get; set; }
    public string JoinCol { get; set; }
    public string JrnlDate { get; set; }
    public string JrnlPfx { get; set; }

    public RawData(string csvString)
    {
        string[] citData = csvString.Replace(", ", "").Replace(".,", ".").Split(',');

        try
        {
            FirstAccount = citData[0];
            AccountNoDv = citData[1];
            AcctNo = citData[2];
            AccNoL = citData[3];
            AcctNumDv = citData[4];
            AcctPfx = citData[5];
            AcctPfxPrt = citData[6];
            AcctTypeDv = citData[7];
            AdvNo = citData[8];
            AllPrtFlag = citData[9];              
            Amt = citData[10];
            AmtGle = citData[11];
            BaseGle = citData[12];
            CntCat = citData[13];
            ColdPrtFlag = citData[14];
            CostDv = citData[15];
            CostOvrdFlagDv = citData[16];
            CrAcctDv = citData[17];
            CrAcctDvGle = citData[18];
            CrossPostingFlag = citData[19];
            CrossPostCat = citData[20];
            CtrlNo = citData[21];
            CtrlTypeDv = citData[22];
            DescReqdDv = citData[23];
            DrAcctDv = citData[24];
            GLDistAcctDv = citData[25];
            GLDistDv = citData[26];
            GrpNoDv = citData[27];
            IdPortDateTimeFmtCat = citData[28];
            InactivityDv = citData[29];
            JoinCol = citData[30];
            JrnlDate = citData[31];
            JrnlPfx = citData[32];
        }
        catch (Exception ex)
        {
            Console.WriteLine("Something went wrong. " + ex.ToString());           
        }
    }
}
编辑2:图像中的AllAccounts实际上是'AccountNoDv',并且实际上有许多不同的字段具有像'AccountNoDv'(AllAccounts)这样的倍数,但我们可能会删除它们,因为这不是最终导出。截至目前,我最担心的两个领域是AccountNoDv和Amt。

2 个答案:

答案 0 :(得分:1)

尝试这样的事情:

   foreach (string line in lines)
   {
      RawData temp = new RawData(line);
      var AllAccounts = temp.AccountNoDv.split(' ');
      var Amts = temp.Amt.split(' ');
      if (AllAccounts.Length() == Amts.Length() && Amts.Length() > 1) {
        // We have multiple values!
        reduced++;
        for (int i = 0; i < AllAccounts.Length(); i++) {
          RawData temp2 = RawDataCopy(temp); // Copy the RawData object
          temp2.AccountNoDv = AllAccounts[i];
          temp2.Amt = Amts[i];
          total++;
          data.Add(temp2);
        }
      }
      else {
        total++;
        if (!(temp.FirstAccount.Length == 0 || temp.FirstAccount == "1ST-ACCT-NO"))
        {
           reduced++;
           data.Add(temp);
         }
       }
    }

private RawData RawDataCopy(RawData copyfrom) {
  // Write a function here that returns an exact copy from the one provided
  // You might have to create a parameterless constructor for RawData
  RawData RawDataCopy = new RawData();
  RawDataCopy.FirstAccount = copyfrom.FirstAccount;
  RawDataCopy.AccountNoDv = copyfrom.AccountNoDv;
  RawDataCopy.AcctNo = copyfrom.AcctNo;
  // . . . . . . . .
  RawDataCopy.JrnlPfx = copyfrom.JrnlPfx;
  return RawDataCopy;
}

然后还向RawData类添加无参数构造函数:

public RawData()
{
}

实现ICloneable界面并调用Clone()函数而不是RawDataCopy函数可能更为性感,但它可以解决这个问题。

答案 1 :(得分:0)

在Linq中,您可以使用SelectMany来增加列表中的元素数量。这是一个如何做到这一点的粗略例子。我假设AllAccounts和Amt中的子元素数量是相同的。更强大的解决方案将检查这些问题。

因此,在您加载数据列表之后:

var expandedData =
   data.SelectMany(item => 
      // split amount (will just return one item if no spaces)
      item.Amt.Split(" ".ToCharArray())
      // join this to the split of all accounts
      .Zip(item.AllAccounts.Split(" ".ToCharArray()),
      // return the joined item as a new anon object
       (a,b) => new { amt=a, all=b }),
      // take the original list item and the anon object and return our new item
      (full,pair) => { full.Amt = pair.amt; full.AllAccounts = pair.all; return full; }));

现在,您将拥有一个数据项列表,其中多个项目已展开到列表中。

我没有要测试的测试数据,所以我可能会有一些小错字 - 但我提出了很多意见,以使Linq尽可能清晰。


以下是我在LinqPad中为自己写的简单示例,以确保我了解SelectMany的工作原理:

string [] list = { "a b c d","e","f g" };

var result = list.SelectMany((e) =>
             e.Split(" ".ToCharArray()), 
             (o,item) => new { org = o, item = item}).Dump();