2010-02-08 2 views
3

XLS 또는 CSV 파일과 같은 입력 파일을 시스템의 개체에 매핑하는 가장 좋은 방법을 찾아 내려고했습니다. 조금 더 넓혀 보겠습니다. 나는 다음과 같은 개체가 :입력 파일을 동적으로 매핑하는 C# 접근 방식

주소 전화 번호 이메일 이

내가 얻을 수있는 입력 파일이 가끔, 변화 등 :

회사 연락

각과 같은 변수 변수를 열 머리말 일 때가 있고 때로는 열 배열과 숫자가 때때로 변경됩니다. 다음과 같이가 볼 수 있었다 "회사"는 "addres1"및 기업 부설 "PHONE1"가됩니다

COMPANY   - CONTACT  - ADDRESS  - PHONE 
---------------------------------------------------------------------- 
company1   contact1  address1  phone1 
company1   contact2  address2 
company2   contact3      phone2 
        contact4  address3 

위의 쇼는 "contact1는"자신의 목적이지만, 같은 "company1"가 그 부모 개체.

"연락처 2"(전화 제외)도 마찬가지입니다.

"contact4"에는 부모 개체가 없으므로 "address3"은 회사가 아니라 연락처에 속합니다.

내 생각은 지금까지 다음과 같은 목적을 가지고 다음과 같습니다.

매핑 - (내가 그것을 구현하는 방법을 잘 모르겠습니다 곳이다 그것은 열을 변수에 매핑하는 방법을 말해야한다, 소유권/계층 구조 - 예를 들어, 회사 주소)

IMappingLoader있다 - (로드 매핑 개체를)

- XmlMappingLoader

- DbMappingLoader

IDataLoader은 -

XLSLoader - - CSVLoader

그래서 매핑을로드 할 것, 데이터 집합에로드 된 데이터와 올바른 개체를 반환

는 (데이터 집합에 데이터를로드합니다).

내가 접근하는 가장 좋은 방법은 매핑 부분을 수행하는 방법입니다. 어떤 열이 어떤 객체에 속해야 하는지를 말할 수있는 방법.

모든 조언을 주셔서 감사합니다.

답변

1

귀하의 파서 그렇지 않으면 특정 개체 속성에 데이터를 매핑 할 수 없습니다 .... 당신의 컬럼에 대해 알고 있어야 할 것입니다. 물론 읽지 않은 순서에 따라 정보를 저장할 수있는 색인 된 속성 클래스를 도입하지 않는 한.

파서 팩터를 생성하고 파일의 확장자에 따라 올바른 파서를 반환해야합니다.

public class Record 
{ 
    private Dictionary<int, string> items = new Dictionary<int, string>(); 
    private int propCount; 

    public Record(int size) 
    { 
     // populate array with empty strings 
     for(int i = 0; i <= size -1; i++) 
      items.Add(i, String.Empty); 
     propCount = size; 
    } 

    public string this[int index] 
    { 
     get { return items[index]; } 
     set { items[index] = value; } 
    } 

    public int PropertyCount { get { return propCount; } } 
} 

public interface IRecordParser 
{ 
    string FileName { get; set; } 
    string[] GetHeadings(); 
    bool HasHeaders { get; set; } 
    void GoToStart(); 
    Record ParseNextRecord(); 
} 

public abstract class RecordParser 
{ 
    public string FileName { get; set; } 
    public bool HasHeaders { get; set; } 
    public abstract string[] GetHeadings(); 
    public abstract void GoToStart(); 
    public abstract Record ParseNextRecord();  
} 

public class ExcelRecordParser : RecordParser, IRecordParser 
{ 
    public ExcelRecordParser() 
    { 
    } 

    public override string[] GetHeadings() 
    { 
     if (HasHeaders) 
      // return column headings 
     else 
      // return default headings from settings file 
    } 

    public override void GoToStart() 
    { 
     // navigate to first row (or +1 if HasHeaders is true) 
    } 

    public override Record ParseNextRecord() 
    { 
     var headers = GetHeadings(); 
     var r = new Record(headers.Length); 

     // enumerate rows, then for each row do... 
     for(int i = 0; i <= headers.Length - 1; i++) 
      r[i] = row[i]; 

     return r; 
    } 
} 

public class CsvRecordParser : RecordParser, IRecordParser 
{ 
    public CsvRecordParser() 
    { 
    } 

    public override string[] GetHeadings() 
    { 
     if (HasHeaders) 
      // return first row split as headings 
     else 
      // return default headers from settings file 
    } 

    public override void GoToStart() 
    { 
     // navigate to start of file (or +1 if HasHeaders is true) 
    } 

    public override Record ParseNextRecord() 
    { 
     var headers = GetHeadings(); 
     var r = new Record(headers.Length); 

     // enumerate lines, then for each line do... 
     for(int i = 0; i <= headers.Length - 1; i++) 
      r[i] = line[i]; 

     return r; 
    } 
} 

public static class RecordParserFactory 
{ 
    public static IRecordParser Create(string ext) 
    { 
     switch (ext) 
     { 
      case ".xls": 
       return new ExcelRecordParser() as IRecordParser; 
      case ".csv": 
       return new CsvRecordParser() as IRecordParser; 
      default: 
       return null; 
     } 
    } 
} 

사용

// would return an instance of CSV Parser 
string file = @"C:\Data\MyRecords.csv"; 
IRecordParser parser = RecordParserFactory.Create(System.IO.Path.GetExtension(file)); 

// would return an instance of Excel Parser 
string file = @"C:\Data\MyRecords.xls"; 
IRecordParser parser = RecordParserFactory.Create(System.IO.Path.GetExtension(file)); 

이 경우 다른 파서를 추가 할 수 있도록 할 미래 예를 들어, 귀하의 파일 형식 변경 XML, 바이너리 등

+0

안녕하세요 제임스,이 부분이 제가 만족하며 매우 비슷한 것을 구현했습니다. 나는 내가 간접적으로 그것을 복잡하게하려고 노력하고 있었다라고 생각한다. 비즈니스가 열과 매핑을 자동으로 설정하여 새로운 데이터를 동적으로로드 할 수 있도록하고 싶습니다. 그러나 비즈니스 로직은 변경 될 수 있고 변경되어서는 안되기 때문에 올바른 해결책을 제시해 줄 수있는 좋은 길을 찾았습니다. 감사합니다 :) – Jon

+0

@ 존, 도와 드리겠습니다. 동적 인 정보를 분석하는 것은 항상 어렵지만, 필자의 시스템은 파싱 할 데이터에 대해 최소한 * 뭔가를 알아야 할 필요가 있다고 말합니다. 그렇지 않으면 매핑하는 것이 불가능합니다. 물론 순전히 데이터가 저장되는 순서대로 내려지지 않는 한, 리플렉션을 사용하거나 클래스를 업데이트하여 인덱스 된 속성을 지원할 수도 있습니다. 내 대답을 업데이트하여 내 뜻을 알려줄 것입니다. – James

+1

@ 존, 내 업데이트 된 답변을 참조하십시오. 이제 인덱스 된 속성 기반 클래스가 포함됩니다. 기본적으로 원하는만큼의 속성을 가질 수 있으며 정보의 순서에 따라 항상 채워집니다. Record 클래스를 쉽게 업데이트하여 크기가 아닌 머리글 목록을 가져온 다음 머리글을 기반으로 정보를 가져올 수 있습니다. 그러나 가능한 한 제네릭을 사용하려면 색인을 붙이십시오. – James

관련 문제