Tuesday, September 16, 2014

Generate a list of objects – Part 2

In my previous post I showed a c# Linq extension method for LINQPad that will create a list of objects from your database as C# code that you can paste in visual studio so you don’t have to manually new up an object and initialize its numerous properties.  There was one limitation in the last edition and that was it didn’t work with IQueryable<T> and also it wasn’t as seamless as you are used to writing linq queries. For example, I had to specify the name of the object “Person” as shown in the code below in the GetClist(“Person”) function.  I wanted to make it better. 
var people = from p in Persons
select new
{
   p.BusinessEntityID,
 p.PersonType,
   p.NameStyle,
    p.Title,
    p.FirstName,
    p.MiddleName,
   p.LastName,
 p.Suffix,
   p.EmailPromotion,
   p.AdditionalContactInfo,
    p.Demographics,
 p.Rowguid,
  p.ModifiedDate
};
people.Take(2).ToList().GetClist("Person");

Imagine you had bunch of orders and you wanted to print out C# code listing orders and related customers. In my latest attempt it works like below code listing. Much cleaner and concise that way you are used to writing lamda expressions.
Orders.Take(2)
.ToClist(x => x.Customer)
.ToClist();

Notice: GetClist() function is renamed to ToClist().
new List() {
new Orders() {
OrderID = 10248,
CustomerID = "VINET",
EmployeeID = 5,
OrderDate = Convert.ToDateTime("7/4/1996 12:00:00 AM"),
RequiredDate = Convert.ToDateTime("8/1/1996 12:00:00 AM"),
ShippedDate = Convert.ToDateTime("7/16/1996 12:00:00 AM"),
ShipVia = 3,
Freight = 32.3800,
ShipName = "Vins et alcools Chevalier",
ShipAddress = "59 rue de l'Abbaye",
ShipCity = "Reims",
SHIPREGION = null ,
ShipPostalCode = "51100",
ShipCountry = "France"
},
new Orders() {
OrderID = 10249,
CustomerID = "TOMSP",
EmployeeID = 6,
OrderDate = Convert.ToDateTime("7/5/1996 12:00:00 AM"),
RequiredDate = Convert.ToDateTime("8/16/1996 12:00:00 AM"),
ShippedDate = Convert.ToDateTime("7/10/1996 12:00:00 AM"),
ShipVia = 1,
Freight = 11.6100,
ShipName = "Toms Spezialitäten",
ShipAddress = "Luisenstr. 48",
ShipCity = "Münster",
SHIPREGION = null ,
ShipPostalCode = "44087",
ShipCountry = "Germany"
}
};
-----------
new List() {
new Customers() {
CustomerID = "VINET",
CompanyName = "Vins et alcools Chevalier",
ContactName = "Paul Henriot",
ContactTitle = "Accounting Manager",
Address = "59 rue de l'Abbaye",
City = "Reims",
REGION = null ,
PostalCode = "51100",
Country = "France",
Phone = "26.47.15.10",
Fax = "26.47.15.11"
},
new Customers() {
CustomerID = "TOMSP",
CompanyName = "Toms Spezialitäten",
ContactName = "Karin Josephs",
ContactTitle = "Marketing Manager",
Address = "Luisenstr. 48",
City = "Münster",
REGION = null ,
PostalCode = "44087",
Country = "Germany",
Phone = "0251-031259",
Fax = "0251-035695"
}
};

With the above code, you can show first two orders and also who placed them. Lets take it one level deep.  In the next query, you can find out orderdetails and find its related orders and take only distinct orders and list customers who placed those orders as C# code.
OrderDetails.Take(5)
.ToClist(x => x.Order).DistinctBy(z => z.OrderID)
.ToClist(y => y.Customer)
.ToClist();

For simplicity, I am not showing results of the query.  Now the code that makes this happen.
//ToClist --- on IQueryable.
 public static IQueryable ToClist(this IQueryable query, Expression> predicate)
 {
  var result = predicate.Compile(); 
  var tresult = from x in query.ToClist()
       select result.Invoke(x); 
  return tresult;
 }
 //ToClist --- on IEnumerable.
 public static IQueryable ToClist(this IEnumerable query, Expression> predicate)
 { 
  var result = predicate.Compile(); 
  var tresult = from x in query.AsQueryable().ToClist()
       select result.Invoke(x);
  return tresult;
 }
 public static IQueryable ToClist(this IQueryable value)
   {   
     Type typeName = value.GetType();  
  Type typeList = value.GetType().GetGenericArguments()[0];          
  
  var listBuilder = new StringBuilder();
      listBuilder.AppendLine(String.Format("new List<{0}>() {{", typeList.Name));                
        foreach (var element in value.ToList())
      {
   
            Type type = element.GetType();
   
   var memberInfo = type.GetMembers();
   var fields = type.GetFields();
   
   var field = fields[0].Name;
   
   var val = fields[0].GetValue(element);
   
   var properties = type.GetProperties(BindingFlags.Public);   
   
   var classBuilder = new StringBuilder();
          classBuilder.AppendLine(String.Format(@"new {0}() {{", typeList.Name));
          List lstElements = new List();
           foreach (FieldInfo p in type.GetFields())
            {
               if (p.GetValue(element) != null)
                {               
                    if (p.GetValue(element).GetType().Name =="DateTime")
                    {
                       lstElements.Add(String.Format(@"{0} = Convert.ToDateTime(""{1}"")", p.Name, p.GetValue(element)));
                  }else if(p.GetValue(element).GetType().Name == "String"){
                       lstElements.Add(String.Format(@"{0} = ""{1}""", p.Name, p.GetValue(element))); 
                 }else if(p.GetValue(element).GetType().Name == "Decimal"){
                      lstElements.Add(String.Format(@"{0} = {1}",p.Name, p.GetValue(element))); 
                  }else if(p.GetValue(element).GetType().Name == "Int32"){
                        lstElements.Add(String.Format(@"{0} = {1}",p.Name, p.GetValue(element))); 
    }else if(p.GetValue(element).GetType().Name == "Int64"){
                        lstElements.Add(String.Format(@"{0} = {1}",p.Name, p.GetValue(element))); 
                  }else if(p.GetValue(element).GetType().Name == "Boolean"){
                      lstElements.Add(String.Format(@"{0} = {1}",p.Name, p.GetValue(element))); 
                  }else if(p.GetValue(element).GetType().Name == "Guid"){
                     lstElements.Add(String.Format(@"{0} = new Guid(""{1}"")",p.Name, p.GetValue(element))); 
                    }else{      
                    }               
                } else{     
         lstElements.Add(String.Format(@"{0} = null ",p.Name.ToUpper())); 
    }
            }           
            for(int i = 0; i < lstElements.Count;i++){
               if (i == lstElements.Count - 1)
             {
                   classBuilder.Append(String.Format("{0}",(lstElements.ToList()[i].ToString())));
             }else{
                  classBuilder.AppendLine(String.Format("{0},",(lstElements.ToList()[i].ToString())));
                }
           }       
            listBuilder.AppendLine(classBuilder.ToString());
            listBuilder.AppendLine(@"},");      
        }
       var preFinal = listBuilder.ToString().Remove(listBuilder.ToString().LastIndexOf(','), 1);               
        var finalValue = String.Format(@"{0}}};", preFinal);
        Console.WriteLine(finalValue);
  return value;
   }

Let me know if you have any feedback in the comments below.