我正在逐行读取excel。各列标题位于第2行。但数据从第4行开始。 我想首先检查列标题,并将第4行的值分别放到关联的模型属性中。
所以我想在for循环中使用case语句而不是if else check。
但它只在第一种情况下破裂。我知道这是有目的的,但还有其他更有效的方法吗?
ListGroupMembershipUploadInput gl = new ListGroupMembershipUploadInput();
for (int rw = 4; rw <= ws.Dimension.End.Row; rw++)
{
//Dictionary<string, string> groupMembershipUploadDict = new Dictionary<string, string>();
int headerCol = 2;
GroupMembershipUploadInput gm = new GroupMembershipUploadInput();
for (int col = ws.Dimension.Start.Column; col <= ws.Dimension.End.Column; col++)
{
string val = ws.Cells[headerCol, col].Value.ToString();
switch (ws.Cells[headerCol, col].Value.ToString())
{
case "Code for the particular Chapter(example,'12345' )" :
gm.chpt_cd = (ws.Cells[rw, col].Value ?? null).ToString();
break;
case "Existing Constituent Master Id" :
gm.cnst_mstr_id = (ws.Cells[rw, col].Value ?? null).ToString();
break;
case "Prefix of the constituent(Mr, Mrs etc)" :
gm.cnst_prefix_nm = (ws.Cells[rw, col].Value ?? null).ToString();
break;
case "First Name of the constituent(Mike)" :
gm.cnst_first_nm = (ws.Cells[rw, col].Value ?? null).ToString();
break;
case "Middle Name of the constituent(R.)" :
gm.cnst_middle_nm = (ws.Cells[rw, col].Value ?? null).ToString();
break;
case "Last Name of the constituent(Andrien)" :
gm.cnst_last_nm = (ws.Cells[rw, col].Value ?? null).ToString();
break;
case "Address Line 1(Home) - (431 Washington Blvd)" :
gm.cnst_addr1_street1 = (ws.Cells[rw, col].Value ?? null).ToString();
break;
}
gl.GroupMembershipUploadInputList.Add(gm);
}
}
这是我建立的模型类。
public class GroupMembershipUploadInput
{
public string chpt_cd {get;set;}
public string cnst_mstr_id {get;set;}
public string cnst_prefix_nm {get;set;}
public string cnst_first_nm {get;set;}
public string cnst_middle_nm {get;set;}
public string cnst_last_nm {get;set;}
public string cnst_addr1_street1 {get;set;}
}
public class ListGroupMembershipUploadInput
{
public List<GroupMembershipUploadInput> GroupMembershipUploadInputList { get; set; }
}
所以我想将excel数据转换为具有空值的模型对象列表。
答案 0 :(得分:0)
你执行
gl.GroupMembershipUploadInputList.Add(gm);
内部for循环内部的。这意味着在评估每列后添加对象。因此,该对象可以多次添加到列表中。
在内部for循环之后移动将对象添加到列表的行。
此外,您不会初始化GroupMembershipUploadInputList
类中的属性ListGroupMembershipUploadInput
。所以它为null并且在尝试将第一个对象添加到列表时,您将获得NullReferenceException
。
您需要创建列表:
public class ListGroupMembershipUploadInput
{
public List<GroupMembershipUploadInput> GroupMembershipUploadInputList { get; set; } = new List<GroupMembershipUploadInput>();
}
答案 1 :(得分:0)
你需要做这样的事情来摆脱switch
陈述:
ListGroupMembershipUploadInput gl = new ListGroupMembershipUploadInput();
int headerCol = 2;
Dictionary<string, int> map = Enumerable
.Range(ws.Dimension.Start.Column, ws.Dimension.End.Column - ws.Dimension.Start.Column + 1)
.ToDictionary(col => ws.Cells[headerCol, col].Value.ToString(), col => col);
for (int rw = 4; rw <= ws.Dimension.End.Row; rw++)
{
gl.GroupMembershipUploadInputList.Add(new GroupMembershipUploadInput()
{
chpt_cd = ws.Cells[rw, map["Code for the particular Chapter(example,'12345' )"]].Value.ToString(),
cnst_mstr_id = ws.Cells[rw, map["Existing Constituent Master Id"]].Value.ToString(),
cnst_prefix_nm = ws.Cells[rw, map["Prefix of the constituent(Mr, Mrs etc)"]].Value.ToString(),
cnst_first_nm = ws.Cells[rw, map["First Name of the constituent(Mike)"]].Value.ToString(),
cnst_middle_nm = ws.Cells[rw, map["Middle Name of the constituent(R.)"]].Value.ToString(),
cnst_last_nm = ws.Cells[rw, map["Last Name of the constituent(Andrien)"]].Value.ToString(),
cnst_addr1_street1 = ws.Cells[rw, map["Address Line 1(Home) - (431 Washington Blvd)"]].Value.ToString(),
});
}
这有效地将gl.GroupMembershipUploadInputList.Add(gm);
移到了内部for
循环之外。
它还使您的代码更小,更易于阅读。
答案 2 :(得分:0)
回答你的问题“还有其他更有效的方法吗?”
1)如果要使用Office Interop,逐个单元格读取不是最有效的方法。人们常常不了解一种不那么明显的方式。
这将一次性返回二维数组,然后通过循环执行循环。您仍然需要手动跳过第二行,空值并处理转换。但这会更快,更清洁 :
Worksheets("Sheet1").Range("A1:D10").Value
2)最有效的方法是使用OleDB,然后你不需要安装Office ,只需免费组件Microsoft Access Database Engine 2010 Redistributable(注意:有x86和x64版本,必须是你的应用)
下面是我编译的代码草稿/代码段,很可能无法正常工作,但这些涉及缅因州的和平。这个想法是你使用excel中的数据,比如数据库和表。最好的部分是你获得了IDataReader,因此你逐个读取行而不将所有内容加载到内存中,所以除了速度之外,这也是RAM方式。
private IDataReader OpenReader()
{
_strConn = String.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 12.0;HDR={1};IMEX=1;TypeGuessRows=0;ImportMixedTypes=Text\"",
_fileName, Configuration.HasHeaders ? "Yes" : "No");
conn = new OleDbConnection(_strConn);
conn.Open();
var schemaTable = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });
string sheet = schemaTable.Rows[0]["TABLE_NAME"].ToString();
var schemaTableColumns = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Columns, new object[] { null, null, sheet, null });
// I am taking 1-st sheet here for simplicity
string sheetName = schemaTable
.Rows[0]["TABLE_NAME"].ToString();
var cmd = new OleDbCommand(String.Format("SELECT * FROM [{0}]", sheetName), conn);
cmd.CommandType = CommandType.Text;
return cmd
.ExecuteReader(CommandBehavior.Default);
}
PS。我决定采用最后一个选项,如果需要,我可以在这里给你更多信息。