2014-04-18 3 views
2

Linq-To-SQL 쿼리에서 대용량 데이터 집합 (IEnumerable[Table] - 속성 클래스 개체)을 가지고 있으며이 데이터베이스에서 CSV 파일을 생성해야합니다. 데이터 집합을 반복하고 각 항목에 대해 다양한 서식 옵션을 사용하여 항목의 각 속성 값을 문자열로 변환합니다.MemoryCache를 사용하여 다양한 객체를 문자열로 빠르게 변환하는 방법은 무엇입니까?

Type t = typeof(T); 
var properties = t.GetProperties(); 

foreach (var item in list) 
{ 
    foreach (var property in properties) 
    { 
     // This is made using delegates, but whatever 
     object value = property.GetValue(item, null); 
     // convert to string and feed to StringBuilder 
    } 
} 

문제는 변환을 실행하면 쿼리를 실행하는 데 더 오래 걸리는 것입니다. 데이터 세트에는 지나치게 비정규 화 된 데이터가 포함되어 있습니다. 많은 항목에는 동일한 값을 갖는 동일한 속성이 있고 다른 값을 갖는 일부 속성 만 있습니다. 각 속성 값은 데이터 집합의 각 항목에 대해 개별적으로 변환됩니다. 그래서 내 코드는 동일한 데이터를 동일한 문자열로 반복해서 변환합니다. 그리고 어떻게 든 SQL 쿼리를 변경하지 않고이 속도를 향상시키고 싶습니다.

MemoryCache class처럼 보이지만 각각의 개체에 대해 고유 한 키를 만들어야합니다. 나는 그러한 키를 어떻게 안정적이고 효율적으로 만들 수 있는지 알 수 없다.

다른 유형의 객체에 대한 변환 결과를 캐시 할 수 있도록 MemoryCache을 어떻게 사용합니까?

답변

0

속도를 높이려면 ExpressionTrees를 MemoryCache 이상으로 제안하십시오. 이것은 당신이 읽고 싶은 중첩 된 객체가 없다고 가정하고 첫 번째 항목에 리플렉션을 사용할 수 있으며 IEnumerable의 각 항목에 대해 동일합니다 - 문제의 예제 코드에서 올바른 것으로 보입니다.

또한 큰 파일이라면 파일에 직접 작성하여 StringBuilder 대신 FileStream으로 직접 설정하는 것이 좋습니다.

public class CSV 
{ 
    public static StringBuilder ToCSV(IEnumerable list) 
    { 
     Func<object, object[]> toArray = null; 
     var sb = new StringBuilder(); 

     // Need to initialize the loop and on the first one grab the properties to setup the columns 
     foreach (var item in list) 
     { 
      if (toArray == null) 
      { 
       toArray = ItemToArray(item.GetType()); 
      } 
      sb.AppendLine(String.Join(",", toArray(item))); 
     } 

     return sb; 
    } 

    private static Func<object, object[]> ItemToArray(Type type) 
    { 
     var props = type.GetProperties().Where(p => p.CanRead); 
     var arrayBody = new List<Expression>(); 

     // Create a parameter to take the item enumeration 
     var sourceObject = Expression.Parameter(typeof (object), "source"); 
     // Convert it to the type that is passed in 
     var sourceParam = Expression.Convert(sourceObject, type); 

     foreach (var prop in props) 
     { 
      var propType = prop.PropertyType; 

      if (IsValueProperty(propType)) 
      { 
       // get the value of the property 
       Expression currentProp = Expression.Property(sourceParam, prop); 
       // Need to box to an object if value type 
       if (propType.IsValueType) 
       { 
        currentProp = Expression.TypeAs(currentProp, typeof (object)); 
       } 
       // Add to the collection of expressions so we can build the array off of this collection 
       arrayBody.Add(currentProp); 
      } 
     } 
     // Create an array based on the properties 
     var arrayExp = Expression.NewArrayInit(typeof (object), arrayBody); 

     // set a default return value of null if couldn't match 
     var defaultValue = Expression.NewArrayInit(typeof (object), Expression.Constant(null)); 

     //Set up so the lambda can have a return value 
     var returnTarget = Expression.Label(typeof (object[])); 
     var returnExpress = Expression.Return(returnTarget, arrayExp, typeof (object[])); 
     var returnLabel = Expression.Label(returnTarget, defaultValue); 

     //Create the method 
     var code = Expression.Block(arrayExp, returnExpress, returnLabel); 
     return Expression.Lambda<Func<object, object[]>>(code, sourceObject).Compile(); 
    } 


    private static bool IsValueProperty(Type propertyType) 
    { 
     var propType = propertyType; 

     if (propType.IsGenericType && propType.GetGenericTypeDefinition() == typeof (Nullable<>)) 
     { 
      propType = new NullableConverter(propType).UnderlyingType; 
     } 

     return propType.IsValueType || propType == typeof (string); 
    } 
}