using system.Linq.dynamic
public class data
{
public int column1{ get; set; }
public int column2{ get; set; }
public string column3{ get; set; }
}
List<data> ListOfdata=new List<data>();
for(i=1:i<10;i++)
{
data newdata=new data();
newdata.column1=i;
newdata.column2=i+1;
ListOfdata.Add(newdata)
}
condition1="column1!=Null AND column1=column2";
var filter=ListOfdata.where(condition).Tolist();
So here when i pass
condition="column1!=Null AND column1=3" i will get the data filter outoff ListOfdata
but not able to get filter data with
condition=condition1;
I used your code (with a little adjustment) and it runs:
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic;
static void Main(string[] args)
{
List<data> ListOfdata = new List<data>();
for (int i = 1; i < 10; i++)
{
data newdata = new data();
newdata.column1 = i;
newdata.column2 = i + 1;
ListOfdata.Add(newdata);
}
//below I update the boolean condition, it needs double == for comparison
// so column1 == column2-1 will be evaluated correctly
string condition1 = "column1!=Null AND column1==column2-1";
//used 'condition1' instead of 'condition'
var filter = ListOfdata.Where(condition1).ToList();
// HERE filter.Count() give me 9 !!
}
public class data
{
public int column1 { get; set; }
public int column2 { get; set; }
public string column3 { get; set; }
}
There is a detailed description for how to create a dynamic query for LINQ:
This Query:
_dbEntities.Customers.Where(cust => cust.CustomerId == 10).FirstOrDefault();
looks like this in a dynamic way:
ParameterExpression pe = Expression.Parameter(Customer, "cust");
var _prpToUse = Expression.Property(pe, "CustomerId");
var _cnstToUse = Expression.Constant(10);
var qry = Expression.Equal(_prpToUse, _cnstToUse);
MethodCallExpression whereExpression = Expression.Call(
typeof(Queryable),
"Where",
new Type[] { lst.ElementType },
lst.Expression,
Expression.Lambda<Func<Customer, bool>>(qry, new
ParameterExpression[] { pe }));
lstData.Provider.CreateQuery<Customer>(whereExpression).FirstOrDefault();
Check out: https://www.c-sharpcorner.com/UploadFile/b1df45/dynamic-query-using-linq/
Hope this helps you.
Related
At the beginning I am aware that there are similar questions, but mine is a little bit different.
I implemented a function that allows the user to select the columns he wants to see.
I've created a stored procedure that gets all column names from the UserColumns table, creates a dynamic sql query and then runs the exec (#command) query. The functionality described above works very well, but there are more requirements that I can't handle this way.
There is TasksViewModel:
public class TasksViewModel
{
public List<Dictionary<List<string>, List<List<object>>>> Tasks { get; set; }
public List<UserDefaultStatusesViewModel> UserStatuses { get; set; }
public List<ZgloszenieStatus> TaskStatuses { get; set; }
public TasksViewModel()
{
}
}
Tasks is filled by stored procedure that runs SELECT x,y,z... FROM table... query.
I'm using this method:
private static IEnumerable<Dictionary<List<string>, List<List<object>>>> Read(DbDataReader reader)
{
var dict = new Dictionary<List<string>, List<List<object>>>();
var cols = new List<string>();
for (int temp = 0; temp < reader.FieldCount; temp++)
{
cols.Add(reader.GetName(temp));
}
var items = new List<List<object>>();
while (reader.Read())
{
var tmp = new List<object>();
for (int i = 0; i < reader.FieldCount; i++)
{
tmp.Add(reader.GetValue(i));
}
items.Add(tmp);
}
dict.Add(cols, items);
foreach (var item in dict)
{
}
yield return dict;
}
I find this very overcomplicated, but at the moment I have no idea if there is another way to do this.
I'm using Entity Framework in my application.
Imagine that I'm using List<Tasks> instead of List<Dictionary<List<string>, List<List<object>>>>. Tasks is database table.
public class Tasks
{
public int ID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public DateTime Date { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
User wants to see only ID,Title,Description columns, so the UserColumns table looks like this:
UserId | ColumnName
1 | ID
2 | Title
3 | Description
Is there a way to select specific columns from List<Tasks> based on UserColumns table using Entity Framework ?
You can create the lambda for Column List dynamically
static Func<Tasks, Tasks> CreateSelect(string[] columns)
{
var parameterExpression = Expression.Parameter(typeof(Tasks), "p");
var newExpression = Expression.New(typeof(Tasks));
var bindings = columns.Select(o => o.Trim())
.Select(o =>
{
var pi = typeof(Tasks).GetProperty(o);
var memberExpression = Expression.Property(parameterExpression, pi);
return Expression.Bind(pi, memberExpression);
}
);
var memberInitExpression = Expression.MemberInit(newExpression, bindings);
var lambda = Expression.Lambda<Func<Tasks, Tasks>>(memberInitExpression, parameterExpression);
return lambda.Compile();
}
and create a LINQ query based on that lambda (columnNameList array is rows from UserColumns table)
static void Foo()
{
var columnNameList = new string[] { "ID", "Title", "Description" };
var tasksList = new List<Tasks>
{
new Tasks{ ID=1, Title="T1", FirstName="F1", LastName="L1", Description="D1", Date=DateTime.UtcNow },
new Tasks{ ID=2, Title="T2", FirstName="F2", LastName="L2", Description="D2", Date=DateTime.UtcNow }
};
var tasks = tasksList.Select(CreateSelect(columnNameList)).FirstOrDefault();
}
I hope that answers your question.
Here I have a class List1 and classes List2,ListViewModel for combining two datasets, and I have two different result sets, each list having four values and I need to combine them as a single resultset with 4 rows and need to do the iteration and summation by using the result values in upcoming resultset.
I have tried Both Ways :
Method 1:
var list1 = List1.GetList1();
var list2 = List2.GetList12();
List<ListViewModel> listViewmodelCollection = new List<ListViewModel>();
ListViewModel listViewmodelInstance = new ListViewModel();
foreach (var _list1 in list1)
{
listViewmodelInstance.LocationValues1 = _list1.LocationValues1;
listViewmodelInstance.LocationValues2 = _list1.LocationValues2;
foreach (var _list2 in list2)
{
listViewmodelInstance.LocationValues5 = _list2.LocationValues5;
listViewmodelInstance.LocationValues4 = _list2.LocationValues4;
listViewmodelInstance.RA = _list1.LocationValues1 + _list2.LocationValues4;
listViewmodelCollection.Add(listViewmodelInstance);
}
}
Method2:
List<ListViewModel> listViewmodelCollection = new List<ListViewModel>();
ListViewModel listViewmodelInstance = new ListViewModel();
var x = (from listobj in m.list
from n in m.list2
select new list4
{
LocationValues1 = listobj.LocationValues1,
LocationValues2 = n.LocationValues4,
LocationValues4 = listobj.LocationValues1 + n.LocationValues4
});
-- complete --
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace simple
{
class Program
{
public class List2
{
public string ContinentName { get; set; }
public decimal LocationValues4 { get; set; }
public decimal LocationValues5 { get; set; }
public Nullable<System.DateTimeOffset> CreatedDate { get; set; }
public static List<List2> GetList12()
{
var list2 = new List<List2>
{
new List2{ ContinentName="Asia",LocationValues4=399.23M,LocationValues5=22.90M },
new List2 { ContinentName ="Africa",LocationValues4=199.23M,LocationValues5=22.90M },
new List2 { ContinentName ="Australia",LocationValues4=199.23M,LocationValues5=22.90M },
new List2 { ContinentName ="Pakistan",LocationValues4=199.23M,LocationValues5=22.90M },
};
return list2;
}
}
public class List1
{
public string LocationName { get; set; }
public decimal LocationValues1 { get; set; }
public decimal LocationValues2 { get; set; }
public Nullable<System.DateTimeOffset> CreatedDate { get; set; }
public static List<List1> GetList1()
{
var list1 = new List<List1>
{
new List1 {LocationName="Africa",LocationValues1=199.23M,LocationValues2=22.90M },
new List1 {LocationName="Africa",LocationValues1=299.23M,LocationValues2=24.90M },
new List1 {LocationName="Africa",LocationValues1=399.23M,LocationValues2=25.90M },
new List1 {LocationName="Africa",LocationValues1=499.23M,LocationValues2=26.90M },
};
return list1;
}
}
public class ListViewModel
{
public string LocationName { get; set; }
public decimal LocationValues1 { get; set; }
public decimal LocationValues2 { get; set; }
public Nullable<System.DateTimeOffset> LocationCreatedDate { get; set; }
public decimal RA { get; set; }
public string ContinentName { get; set; }
public decimal LocationValues4 { get; set; }
public decimal LocationValues5 { get; set; }
public Nullable<System.DateTimeOffset> ContinentCreatedDate { get; set; }
}
static void Main(string[] args)
{
var list1 = List1.GetList1();
var list2 = List2.GetList12();
List<ListViewModel> listViewmodelCollection = new List<ListViewModel>();
ListViewModel listViewmodelInstance = new ListViewModel();
foreach (var _list1 in list1)
{
listViewmodelInstance.LocationValues1 = _list1.LocationValues1;
listViewmodelInstance.LocationValues2 = _list1.LocationValues2;
foreach (var _list2 in list2)
{
listViewmodelInstance.LocationValues5 = _list2.LocationValues5;
listViewmodelInstance.LocationValues4 = _list2.LocationValues4;
listViewmodelInstance.RA = _list1.LocationValues1 + _list2.LocationValues4;
listViewmodelCollection.Add(listViewmodelInstance);
}
}
}
Expected Output:
4 Rows
LocationName="Africa",LocationValues1=199.23M,LocationValues2=22.90M,ContinentName="Asia",LocationValues4=399.23M,LocationValues5=22.90M, RA=598.46
LocationName="Africa",LocationValues1=299.23M,LocationValues2=24.90M ,ContinentName ="Africa",LocationValues4=199.23M,LocationValues5=22.90M,RA=465.46
LocationName="Africa",LocationValues1=399.23M,LocationValues2=25.90M ContinentName ="Australia",LocationValues4=199.23M,LocationValues5=22.90M,RA=598.46
LocationName="Africa",LocationValues1=499.23M,LocationValues2=26.90M , ContinentName ="Pakistan",LocationValues4=199.23M,LocationValues5=22.90M.RA=698.46
But current output:
So, this seems messy at best. I'm not sure what your situation is but I would be very nervous about coding to merge 2 different data lists and expecting them to always be equal lengths etc..
I would strongly recommend that you add an interface to both lists so you could at least cast them to a base object and work with them that way instead.
That said I would try to select out the view model attributes via linq from the first set, then iterate through to add the data from the 2nd set and do the computations then.
Example:
var list1 = List1.GetList1();
var list2 = List2.GetList12();
List<ListViewModel> listViewmodelCollection = new List<ListViewModel>();
ListViewModel listViewmodelInstance = new ListViewModel();
listViewmodelCollection.AddRange(list1.Select(l => new ListViewModel()
{
LocationName = l.LocationName,
LocationCreatedDate = l.CreatedDate,
LocationValues1 = l.LocationValues1,
LocationValues2 = l.LocationValues2
}));
for (int i = 0; i < (listViewmodelCollection.Count - 1); i++)
{
var itm2 = list2.ElementAt(i);
if (itm2 != null)
{
listViewmodelCollection[i].ContinentName = itm2.ContinentName;
listViewmodelCollection[i].ContinentCreatedDate = itm2.CreatedDate;
listViewmodelCollection[i].LocationValues4 = itm2.LocationValues4;
listViewmodelCollection[i].LocationValues5 = itm2.LocationValues5;
listViewmodelCollection[i].RA = listViewmodelCollection[i].LocationValues1 + itm2.LocationValues4;
}
}
Given your classes this should get you to the output you wanted, at least for this narrow example.
You can use LINQ to combine the two Lists using the Zip extension method:
var listViewmodelCollection = list1.Zip(list2, (l1, l2) => new ListViewModel {
LocationName = l1.LocationName,
LocationValues1 = l1.LocationValues1,
LocationValues2 = l1.LocationValues2,
ContinentName = l2.ContinentName,
LocationValues4 = l2.LocationValues4,
LocationValues5 = l2.LocationValues5,
RA = l1.LocationValues1+l2.LocationValues4
}).ToList();
Is it possible to create a generic search method where key is unknown? for e.g Key for the List will be passed to the parameter and it performs a like search and return the filtered List.
Code should be something like:
public List<T> LikeSearch<T>(List<T> AllData,T key, string searchString)
{
List<T> _list = new List<T>();
//Perform the search on AllData based on searchString passed on the key
//given
return _list;
}
Uses will be like:
Example 1
List<Users> _users = LikeSearch<Users>(AllUsers,'Name','sam');
Where AllUsers is the list of 100 users.
Example 2
List<Customers> _cust = LikeSearch<Customers>(AllCustomers,'City','London');
Where AllCustomers is the list of 100 Customers.
Please sugest
Assuming key always refers to a public property implemented by whatever type T is, you could do the following:
public static List<T> LikeSearch<T>(this List<T> data, string key, string searchString)
{
var property = typeof(T).GetProperty(key, BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.Instance);
if (property == null)
throw new ArgumentException($"'{typeof(T).Name}' does not implement a public get property named '{key}'.");
//Equals
return data.Where(d => property.GetValue(d).Equals(searchString)).ToList();
//Contains:
return data.Where(d => ((string)property.GetValue(d)).Contains(searchString)).ToList();
}
I think this link will help you ... Questions are different but you could find your answer there.. For reference i am again posting here the answer ...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Linq.Expressions;
using System.Reflection;
namespace Rextester
{
public class Program
{
public static void Main(string[] args)
{
List<Demo> all= new List<Demo>();
all.Add(new Demo{Name="a"});
all.Add(new Demo{Name="ab"});
all.Add(new Demo{Name="abc"});
all.Add(new Demo{Name="cba"});
all.Add(new Demo{Name="bac"});
all.Add(new Demo{Name="ddd"});
var t= Filter(all,"Name","a");
Console.WriteLine(t.Count);
}
public static List<T> Filter<T>(List<T> Filterable, string PropertyName, object ParameterValue)
{
ConstantExpression c = Expression.Constant(ParameterValue);
ParameterExpression p = Expression.Parameter(typeof(T), "xx");
MemberExpression m = Expression.PropertyOrField(p, PropertyName);
MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var containsMethodExp = Expression.Call(m, method, c);
var Lambda= Expression.Lambda<Func<T, bool>>(containsMethodExp, p);
//var Lambda = Expression.Lambda<Func<T, Boolean>>(Expression.Equal(c, m), new[] { p });
Func<T, Boolean> func = Lambda.Compile();
return Filterable.Where(func).ToList();
}
}
public class Demo
{
public string Name{get;set;}
}
}
With the linq method Where
list.Where(x => x.YourKey.Contains(searchString))
Example 1
List<Users> _users = AllUsers.Where(x => x.Name.Contains("sam"));
Example 2
List<Customers> _cust = AllCustomers.Where(x => x.City.Contains("London"));
You can write a method like this otherwise:
public List<T> LikeSearch<T>(List<T> list, Func<T, string> getKey, string searchString)
{
return list.Where(x => getKey(x).Contains(searchString)).ToList();
}
And you can use it like this:
Example 1
List<Users> _users = LikeSearch(AllUsers, x => x.Name, "sam");
Example 2
List<Customers> _cust = LikeSearch(AllCustomers, x => x.City, "London");
EDIT: here a small benchmark about solutions proposed here
I benchmarked only the Contains version of everyone.
With this we can see (depending on your computer and stars...):
InBetween OneProperty: 00:00:00.0026050
Moumit OneProperty: 00:00:00.0013360
Mine OneProperty: 00:00:00.0010390
The two different classes are here to test if the number of properties change something
InBetween LotProperties: 00:00:00.0026378
Moumit LotProperties: 00:00:00.0012155
Mine LotProperties: 00:00:00.0010021
I'm really surprised how Moumit's solution is fast, I expected it to be slower with the compile at runtime. But nevertheless, we can see that GetProperty and GetValue are really slow.
The benchmark code:
static void Main(string[] args)
{
int size = 10000;
Dictionary<string, List<long>> time = new Dictionary<string, List<long>>()
{
{"InBetween OneProperty", new List<long>() },
{"Moumit OneProperty", new List<long>() },
{"Mine OneProperty", new List<long>() },
{"InBetween LotProperties", new List<long>() },
{"Moumit LotProperties", new List<long>() },
{"Mine LotProperties", new List<long>() },
};
List<OneProperty> oneProperties = new List<OneProperty>();
List<LotProperties> lotProperties = new List<LotProperties>();
for (int i = 0; i < size; ++i)
{
oneProperties.Add(new OneProperty() { Key = i.ToString() });
lotProperties.Add(new LotProperties() { Key = i.ToString() });
}
Stopwatch sw = new Stopwatch();
for (int i = 0; i < 1000; ++i)
{
sw.Start();
InBetween.LikeSearch(oneProperties, "Key", "999");
sw.Stop();
time["InBetween OneProperty"].Add(sw.Elapsed.Ticks);
sw.Reset();
sw.Start();
Moumit.Filter(oneProperties, "Key", "999");
sw.Stop();
time["Moumit OneProperty"].Add(sw.Elapsed.Ticks);
sw.Reset();
sw.Start();
Mine.LikeSearch(oneProperties, x => x.Key, "999");
sw.Stop();
time["Mine OneProperty"].Add(sw.Elapsed.Ticks);
sw.Reset();
sw.Start();
InBetween.LikeSearch(lotProperties, "Key", "999");
sw.Stop();
time["InBetween LotProperties"].Add(sw.Elapsed.Ticks);
sw.Reset();
sw.Start();
Moumit.Filter(lotProperties, "Key", "999");
sw.Stop();
time["Moumit LotProperties"].Add(sw.Elapsed.Ticks);
sw.Reset();
sw.Start();
Mine.LikeSearch(lotProperties, x => x.Key, "999");
sw.Stop();
time["Mine LotProperties"].Add(sw.Elapsed.Ticks);
sw.Reset();
}
foreach (string key in time.Keys)
Console.WriteLine($"{key}: {new TimeSpan((long)time[key].Average())}");
Console.ReadKey();
}
class OneProperty
{
public string Key { get; set; }
}
class LotProperties
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
public string D { get; set; }
public string E { get; set; }
public string F { get; set; }
public string G { get; set; }
public string H { get; set; }
public string I { get; set; }
public string J { get; set; }
public string K { get; set; }
public string L { get; set; }
public string M { get; set; }
public string N { get; set; }
public string O { get; set; }
public string P { get; set; }
public string Q { get; set; }
public string R { get; set; }
public string S { get; set; }
public string T { get; set; }
public string U { get; set; }
public string V { get; set; }
public string W { get; set; }
public string X { get; set; }
public string Y { get; set; }
public string Z { get; set; }
public string Key { get; set; }
}
I have the classes
public class MyModel
{
public MyModel()
{
this.Map = new MyMap();
}
public MyMap Map { get; set; }
}
public class MyMap
{
public string MyProperty1 { get; set; }
public int MyProperty2 { get; set; }
}
How can I construct this lambda
Expression<Func<MyModel, string>> exp = m => m.Map.MyProperty1;
manually using Expression Tree?
Like this:
var parameter = Expression.Parameter(typeof (MyModel));
var mapProperty = Expression.Property(parameter, "Map");
var myProperty1 = Expression.Property(mapProperty, "MyProperty1");
var exp = Expression.Lambda<Func<MyModel, string>>(myProperty1, parameter);
You can do this using the PropertyOrField method of Expression, here is a quick example I cooked up using your objects:
var model = new MyModel();
var mapExpr = Expression.PropertyOrField(Expression.Constant(model), "Map");
var propExpr = Expression.PropertyOrField(mapExpr, "MyProperty1");
Expression.Lambda<Func<string>>(propExpr).Compile()(); //Outputs the value of MyProperty1 on the variable called model.
I'm trying to build left outer join queries with Linq Expressions but now I really hit the wall.
What I want to accomplish is the following query:
var q =
from i in ProcessInstances
join dof1 in Queries.DataObjectFieldsQuery(this) on new { instanceId = i.ObjectID, dataId = fields[0,0], fieldId = fields[0,1] } equals new { instanceId = dof1.ProcessInstanceObjectID, dataId = dof1.DataID, fieldId = dof1.FieldID } into dofs1
from dof1 in dofs1.DefaultIfEmpty()
join dof2 in Queries.DataObjectFieldsQuery(this) on new { instanceId = i.ObjectID, dataId = fields[1,0], fieldId = fields[1,1] } equals new { instanceId = dof2.ProcessInstanceObjectID, dataId = dof2.DataID, fieldId = dof2.FieldID } into dofs2
from dof2 in dofs2.DefaultIfEmpty()
join dof3 in Queries.DataObjectFieldsQuery(this) on new { instanceId = i.ObjectID, dataId = fields[2,0], fieldId = fields[2,1] } equals new { instanceId = dof3.ProcessInstanceObjectID, dataId = dof3.DataID, fieldId = dof3.FieldID } into dofs3
from dof3 in dofs3.DefaultIfEmpty()
select new WorkitemListModel
{
InstanceId = i.ObjectID,
FormFieldValue1 = dof1.FieldValue,
FormFieldValue2 = dof2.FieldValue,
FormFieldValue3 = dof3.FieldValue,
};
I have defined the following classes:
public class WorkitemListModel
{
public string InstanceId { get; set; }
public string FormFieldValue1 { get; set; }
public string FormFieldValue2 { get; set; }
public string FormFieldValue3 { get; set; }
}
public class DataObjectField
{
public string ProcessInstanceObjectID { get; set; }
public string DataID { get; set; }
public string FieldID { get; set; }
public string FieldValue { get; set; }
}
public class ModelWithFields<TModel>
{
public IEnumerable<DataObjectField> DataObjectFields { get; set; }
public TModel Model { get; set; }
}
public class OuterKeySelector
{
public string instanceId { get; set; }
public string dataId { get; set; }
public string fieldId { get; set; }
}
I created the GroupJoin expression wich gives no compile errors. (I left out som code here):
var q = dc.Instances;
System.Type modelType = typeof(ModelWithFields<>);
System.Type outerKeyType = typeof(WorkitemListModel);
System.Type resultType = modelType.MakeGenericType(outerKeyType);
//... MemberInitExpression and Expression.Bind
q = q.Provider.CreateQuery(
Expression.Call(
typeof(Queryable),
"GroupJoin",
new[]
{
typeof(WorkitemListModel),
typeof(DataObjectField),
typeof(OuterKeySelector),
resultType,
},
query.Expression,
Expression.Constant(Queries.DataObjectFieldsQuery(dc)),
Expression.Quote(outerLambda),
Expression.Quote((Expression<Func<DataObjectField,OuterKeySelector>>)(
(DataObjectField dof) =>
new OuterKeySelector
{
instanceId = dof.ProcessInstanceObjectID,
dataId = dof.DataID,
fieldId = dof.FieldID
})),
Expression.Quote(resultLambda)));
// selectmany expression
// collectionSelector lambda -- temp.DataObjectFields.DefaultIfEmpty()
ParameterExpression collectionParameter = Expression.Parameter(resultType, "temp");
// This throw an exception
MethodCallExpression collectionCallExpression =
Expression.Call(
typeof(Queryable),
"DefaultIfEmpty",
new System.Type[]
{
typeof(IQueryable<>).MakeGenericType(typeof(DataObjectField))
},
Expression.Property(collectionParameter, resultType.GetProperty("DataObjectFields")));
But in the SelectMany method I'm trying to add DefaultIfEmpty but I get an exception saying:
No generic method 'DefaultIfEmpty' on
type 'System.Linq.Queryable' is
compatible with the supplied type
arguments and arguments. No type
arguments should be provided if the
method is non-generic.
I've tried the switched the typeparams from IQueryable to IEnumerable and event tried to call Enumerable.DefaultIfEmpty with no luck. Perhaps it's something wrong with the PropertyExpression?
I prefer a different overload for Expression.Call using MethodInfo, here is a simple example I have working.
Expression constant = Expression.Constant(new string[] { "a", "b" });
MethodInfo methodInfo = typeof(Enumerable).GetMethods().FirstOrDefault(c => (c as MethodInfo).Name == "DefaultIfEmpty");
methodInfo = methodInfo.MakeGenericMethod(typeof(string));
MethodCallExpression methodExpression = Expression.Call(methodInfo, constant);
I had defined incorrect type parameter of the Expression.Call method. It wasn't IQueryable<DataObjectField> but only DataObjectField. This is what fixed it.
MethodCallExpression collectionCallExpression =
Expression.Call(
typeof(Enumerable),
"DefaultIfEmpty",
new System.Type[]
{
typeof(DataObjectField)
},
Expression.Property(collectionParameter, newResultType.GetProperty("DataObjectFields"))