C# Expression - Getdefault Value or convert int? to int - c#

I have a Class like below
public class GrouppedStockGift
{
public DateTime? TimeCreated { get; set; }
public int? StoreID { get; set; }
public int? UserCreated { get; set; }
public int? WorksID { get; set; }
public int? WorkOrderCode { get; set; }
public decimal? GiftPrice { get; set; }
public decimal? GiftMoney { get; set; }
public int SaleCount { get; set; }
}
I have Create a dynamic expression builder, in some case i need to convert int? to int or getdefaultvalue of int for example
var sumMethodint = typeof(Enumerable).GetMethods()
.Single(x => x.Name == "Sum"
&& x.GetParameters().Count() == 2
&& x.GetParameters()[1]
.ParameterType
.GetGenericArguments()[1] == typeof(int?));
sumMethodint = sumMethodint.MakeGenericMethod(typeof(GrouppedStockGift));
Expression<Func<GrouppedStockGift, int?>> SaleCount = y => y.SaleCount;
var SaleCountExtractor = Expression.Call(sumMethodint, parameter, SaleCount);
bindings.Add(
Expression.Bind(
typeof(GrouppedStockGift).GetProperty("SaleCount"),
SaleCountExtractor));
but when execute last row Exception returned around type mismached
because SaleCount is int but sum method return int?
can any one help me?

You must just change Expression.Call row to
var SaleCountExtractor = Expression.Call(Expression.Call(sumMethodint, parameter, SaleCount), "GetValueOrDefault", Type.EmptyTypes);
in the above code
Expression.Call(exp, "GetValueOrDefault", Type.EmptyTypes);
get default value of int

I assume that problem is in your decision to use the overload of Sum which returns int?. You should use the another overload which gets selecotr of type Func<T, int> and returns int.
var parameter = Expression.Parameter(typeof (IEnumerable<GrouppedStockGift>));
var sumMethodint = typeof(Enumerable).GetMethods()
.Single(x => x.Name == "Sum"
&& x.GetParameters().Count() == 2
&& x.GetParameters()[1]
.ParameterType
.GetGenericArguments()[1] == typeof(int));
sumMethodint = sumMethodint.MakeGenericMethod(typeof(GrouppedStockGift));
Expression<Func<GrouppedStockGift, int>> saleCount = y => y.SaleCount;
var saleCountExtractor = Expression.Call(sumMethodint, parameter, saleCount);
bindings.Add(Expression.Bind(typeof(GrouppedStockGift).GetProperty("SaleCount"),
saleCountExtractor));

Related

Generic Method to convert datatable to list

I'm using below code:
public static List<T> ConvertToList1<T>(DataTable dt)
{
var columnNames = dt.Columns.Cast<DataColumn>()
.Select(c => c.ColumnName)
.ToList();
var properties = typeof(T).GetProperties();
return dt.AsEnumerable().Select(row =>
{
T objT1 = Activator.CreateInstance<T>();
foreach (var pro in properties)
{
if (columnNames.Contains(pro.Name))
{
PropertyInfo? pI = objT.GetType().GetProperty(pro.Name);
pro.SetValue(objT, row[pro.Name] == DBNull.Value ? null : Convert.ChangeType(row[pro.Name], pI.PropertyType));
}
}
return objT1;
}).ToList();
}
But I'm getting error for decimal field having null values.
Invalid cast from 'System.Decimal' to 'System.Nullable`1[[System.Decimal, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral
public class SampleModel
{
public Guid Id { get; set; }
public Guid ProjectId { get; set; }
public string? Code { get; set; } = null!;
public string? Description { get; set; }
public decimal? Quantity1 { get; set; }
public decimal? Quantity2 { get; set; }
}
Can anyone suggest how to fix this?
Um, reading again... You mean that a non-null decimal value in the row cannot be assigned to a nullable decimal? Or did you mean a dbnull that cannot be assigned to the nullable decimal?
You can use the DataRow.IsNull to check if the value is dbnull. In that case you just skip it as the nullable already has default null.
// <CODE SNIP />
if (columnNames.Contains(pro.Name))
{
// if the value was null, just skip it.
if(!row.IsNull(pro.Name))
{
PropertyInfo? pI = objT.GetType().GetProperty(pro.Name);
pro.SetValue(objT, Convert.ChangeType(row[pro.Name], pI.PropertyType));
}
}
I've had a play.
The link from #Ryan Wilson was very useful.
In short, where you have a nullable type, you want to cast to the underlying type. Consider:
decimal? target;
decimal source = 42;
target = source;
This is perfectly reasonable code. We can assign a decimal value to a decimal? variable.
Using Nullable.GetUnderlyingType(myType) returns a type or null if myType is not nullable. Extending the above snippet:
var underlying1 = Nullable.GetUnderlyingType(target.GetType());
var underlying2 = Nullable.GetUnderlyingType(source.GetType());
Here, underlying2 is null, and underlying1 is decimal.
To put this into practice, then, we slightly alter the innermost part of your conversion method to become:
PropertyInfo pI = objT1.GetType().GetProperty(pro.Name);
var targetType = Nullable.GetUnderlyingType(pI.PropertyType) ?? pI.PropertyType;
pro.SetValue(objT1, row[pro.Name] == DBNull.Value
? null
: Convert.ChangeType(row[pro.Name], targetType));
Try following :
public static List<SampleModel> ConvertToList1<T>(DataTable dt)
{
List<SampleModel> results = dt.AsEnumerable().Select(x => new SampleModel()
{
Id = x.Field<Guid>("Id"),
ProjectId = x.Field<Guid>("ProjectId"),
Code = x.Field<string>("Code"),
Description = x.Field<string>("Description"),
Quantity1 = x.Field<decimal>("Quantity1"),
Quantity2 = x.Field<decimal>("Quantity1")
}).ToList();
return results;
}

Add values to a list inside a list Linq

I am having a class like this.
public class CameraModel
{
public int JobId { get; set; }
public int ViewId { get; set; }
public Guid ViewGuid { get; set; }
public string Name { get; set; }
public int ViewNum { get; set; }
public int LayoutID { get; set; }
public List<CameraViewItemModel> CameraViewItems { get; set; }
}
The CameraViewItemModel class is like this:
public class CameraViewItemModel
{
public int JobID { get; set; }
public Guid ViewGuid { get; set; }
public int ViewID { get; set; }
public int CamNum { get; set; }
public Guid ChannelGuid { get; set; }
public string Name { get; set; }
public ActionType Action { get; set; }
}
Now, I am assigning the list of CameraViewItemModel like this:
// get all the cameramodel's
cameraModels = _unitOfWork.Context.CameraViews.Where(m => m.JobId == siteId)
.Select(m => new CameraModel
{
JobId = m.JobId,
ViewId = m.ViewId,
ViewGuid = m.ViewGuid,
Name = m.Name,
ViewNum = m.ViewNum,
LayoutID = m.LayoutId
}).ToList();
// get all the cameraviewitemmodels
cameraViewItemModels =
(from cameraView in _unitOfWork.Repository<CameraViews>().Get(x => x.JobId == siteId).Result
join cameraViewItem in _unitOfWork.Repository<CameraViewItems>().Get(x => x.JobId == siteId)
.Result on cameraView.ViewId equals cameraViewItem.ViewId into CameraViewItemResults
from cameraViewItemResult in CameraViewItemResults.DefaultIfEmpty()
join cameraChannel in _unitOfWork.Repository<CameraChannels>().Get(x => x.JobId == siteId)
.Result on (cameraViewItemResult == null ? new Guid() : cameraViewItemResult.ChannelGuid) equals cameraChannel.ChannelGuid into CameraChannelResults
from cameraChannelResult in CameraChannelResults.DefaultIfEmpty()
select new CameraViewItemModel
{
JobID = cameraView.JobId,
ViewID = cameraView.ViewId,
ViewGuid = cameraView.ViewGuid,
CamNum = cameraViewItemResult.CamNum,
ChannelGuid = cameraChannelResult.ChannelGuid,
Name = cameraChannelResult.Name
}).ToList();
// then do a 'join' on JobId, ViewId and ViewGuid and assign the list of cameraviewitemmodels to cameraModels.
foreach (var cameraModel in cameraModels)
{
cameraModel.CameraViewItems = (from cameraViewItem in cameraViewItemModels
where cameraModel.JobId == cameraViewItem.JobID
&& cameraModel.ViewId == cameraViewItem.ViewID
&& cameraModel.ViewGuid == cameraViewItem.ViewGuid
select cameraViewItem).ToList();
}
return cameraModels;
There are three tables in database:
CameraViews, CameraViewItems, CameraChannels.
CameraViews is the main table. It is left joined with CameraViewItems and CameraChannels to get the desired result. There may not be any data in CameraViewItems and CameraChannels for a corresponding CameraView.
Is it possible to assign the list of CameraViewItemModels to CameraModels in a single linq statement.
Here is a simple way to add values to a sub list, dunno if this is what you mean. You can keep selecting sub lists if that is necessary.
var parent_lst = new List<List<string>>(); // Root/parent list that contains the other lists
var sub_lst = new List<string>(); // Sub list with values
var selected_parent_lst = parent_lst[0]; // Here I select sub list, in this case by list index
selected_parent_lst.Add("My new value"); // And here I add the new value

Argument types do not match Transforming anonymous Expression<Func<T,U>> to non anonymous Expression<Func<T,U>>

Imagine that we have three classes like this:
public class ParentType {
private ParentType() {}
public int Id { get; protected set; }
public SubType Sub { get; protected set; }
}
public class SubType{
private SubType(){}
public int Id { get; protected set; }
public ICollection<ColSubType> ColSubs{get; protected set;}
}
public class ColSubType{
private ColSubType(){}
public int Id { get; protected set; }
public SubType SubType { get; set; }
}
I have an anonymous Expression like this:
x => new
{
x.Id,
Sub = new
{
x.Sub.Id,
ColSubs = x.Sub.ColSubs.Select(u=> new {
u.Id
}).ToList()
}
}
I need to transform it to a non anonymous Expression like this:
x => new ParentType()
{
Id = x.Id,
Sub = new SubType()
{
Id = x.Sub.Id,
ColSubs = x.Sub.ColSubs.Select(u=> new ColSubs(){
Id = u.Id
}).ToList()
}
}
Thanks to #IvanStoev's answer to this question: Variable 'x.Sub' of type 'SubType' referenced from scope '' but it is not defined error I am able to transform the simple Expressions, but when I add x.Sub.ColSubs.Select(...) I get the following error:
System.ArgumentException: Argument types do not match
Following is a code you need to add to the recursive Transform method which handles exactly that scenario, i.e. detect Select method, transform the selector argument, modify the TResult generic type argument of the Select and call it with the new selector, and finally call ToList in case the destination is not IEnumerable<T>:
if (source.Type != type && source is MethodCallExpression call && call.Method.IsStatic
&& call.Method.DeclaringType == typeof(Enumerable) && call.Method.Name == nameof(Enumerable.Select))
{
var sourceEnumerable = call.Arguments[0];
var sourceSelector = (LambdaExpression)call.Arguments[1];
var sourceElementType = sourceSelector.Parameters[0].Type;
var targetElementType = type.GetGenericArguments()[0];
var targetSelector = Expression.Lambda(
Transform(sourceSelector.Body, targetElementType),
sourceSelector.Parameters);
var targetMethod = call.Method.GetGenericMethodDefinition()
.MakeGenericMethod(sourceElementType, targetElementType);
var result = Expression.Call(targetMethod, sourceEnumerable, targetSelector);
if (type.IsAssignableFrom(result.Type)) return result;
return Expression.Call(
typeof(Enumerable), nameof(Enumerable.ToList), new[] { targetElementType },
result);
}

Linq Expression tree Any() issue

Hello I'm having trouble with an expression tree using the .Any() extension method.
Here's my code:
IQueryable<Book> querableBooks = Books.Values.AsQueryable<Book>();
ParameterExpression pe = Expression.Parameter(typeof(Book), "book");
MemberExpression props = Expression.Property(pe, "properties");
ParameterExpression propList = Expression.Parameter(typeof(List<BookProperty>), "properties");
var _test = Expression.Lambda<Func<List<BookProperty>, bool>>(operation, new ParameterExpression[] { propList });
var _Any = Expression.Call(typeof(Enumerable), "any", new Type[] { typeof(BookProperty) }, new Expression[] { propList });
Expression Lamba = Expression.Lambda(_Any, _props);
_test returns {properties => ((bookProperty.type.key == "lingerie") And (bookProperty.value == "1"))}
_Any returns {properties.Any()}
Lambda returns {book.properties => properties.Any()}
The Book class is like this:
public class Book : IBook
{
public int id { get; set; }
//Removed for clarity
public List<BookProperty> properties { get; set; }
}
An the BookProperty class:
public class BookProperty
{
public BookProperty()
{
value = "0";
}
public int id { get; set; }
public int bookId { get; set; }
public Book book { get; set; }
public int typeId { get; set; }
public BookPropertyType type { get; set; }
public string value { get; set; }
}
And BookPropertyType class:
public class BookPropertyType
{
public int id { get; set; }
public string groupe { get; set; }
public string key { get; set; }
public string label { get; set; }
public int order { get; set; }
public string editorType { get; set; }
public string unite { get; set; }
}
So I'm close to it, but I don't how to merge all this correctly to have a query like this
{book.propertie.Any(bookProperty => bookProperty.type.key == "lingerie") And (bookProperty.value == "1")}
Thanks for your help.
If I understand correctly, you are looking for expression like this:
Expression<Func<Book, bool>> bookPredicate = book => book.properties.Any(
bookProperty => bookProperty.type.key == "lingerie" && bookProperty.value == "1");
You can build it dynamically like this:
var book = Expression.Parameter(typeof(Book), "book");
var properties = Expression.PropertyOrField(book, "properties");
var bookProperty = Expression.Parameter(typeof(BookProperty), "bookProperty");
// bookProperty.type.key == "lingerie"
var conditionA = Expression.Equal(
Expression.PropertyOrField(Expression.PropertyOrField(bookProperty, "type"), "key"),
Expression.Constant("lingerie")
);
// bookProperty.value == "1"
var conditionB = Expression.Equal(
Expression.PropertyOrField(bookProperty, "value"),
Expression.Constant("1")
);
// bookProperty.type.key == "lingerie" && bookProperty.value == "1"
var condition = Expression.AndAlso(conditionA, conditionB);
// bookProperty => bookProperty.type.key == "lingerie" && bookProperty.value == "1"
var predicate = Expression.Lambda<Func<BookProperty, bool>>(condition, bookProperty);
// book.properties.Any(bookProperty => bookProperty.type.key == "lingerie" && bookProperty.value == "1")
var anyCall = Expression.Call(
typeof(Enumerable), "Any", new[] { typeof(BookProperty) },
properties, predicate
);
// book => book.properties.Any(...)
var bookPredicate = Expression.Lambda<Func<Book, bool>>(anyCall, book);

Create predicate with nested classes with Expression

I have this :
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
}
public class City
{
public int Id { get; set; }
public string Name { get; set; }
public int ZipCode { get; set; }
}
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int? Age { get; set; }
public City City { get; set; }
public Company Company { get; set; }
}
I'd like a some case generate the predicate like this :
var result = listPerson.Where(x => x.Age == 10).ToList<>();
Or this :
var result = listPerson.Where( x => x.Company.Name == 1234).ToList();
Or this :
var result = listPerson.Where( x => x.City.ZipCode == "MyZipCode").ToList();
Or this :
var result = listPerson.Where( x => x.Company.Name == "MyCompanyName").ToList();
Then I created a "PredicateBuilder", that's work (I get the type, if nullable or not and I build the predicate) when I do this :
BuildPredicate<Person>("Age", 10); I get this : x => x.Age == 10
But I don't how manage when there is an nested property like this :
BuildPredicate<Person>("City.ZipCode", "MyZipCode");
I'd like get this : x => x.City.ZipCode == "MyZipCode"
Or this :
BuildPredicate<Person>("City.Name", "MyName");
I'd like get this : x => x.City.Name == "MyName"
Or this :
BuildPredicate<Person>("Company.Name", "MyCompanyName");
I'd like get this : x => x.Company.Name == "MyCompanyName"
(not intending to duplicate Jon - OP contacted me to provide an answer)
The following seems to work fine:
static Expression<Func<T,bool>> BuildPredicate<T>(string member, object value) {
var p = Expression.Parameter(typeof(T));
Expression body = p;
foreach (var subMember in member.Split('.')) {
body = Expression.PropertyOrField(body, subMember);
}
return Expression.Lambda<Func<T, bool>>(Expression.Equal(
body, Expression.Constant(value, body.Type)), p);
}
The only functional difference between that and Jon's answer is that it handles null slightly better, by telling Expression.Constant what the expected type is. As a demonstration of usage:
static void Main() {
var pred = BuildPredicate<Person>("City.Name", "MyCity");
var people = new[] {
new Person { City = new City { Name = "Somewhere Else"} },
new Person { City = new City { Name = "MyCity"} },
};
var person = people.AsQueryable().Single(pred);
}
You just need to split your expression by dots, and then iterate over it, using Expression.Property multiple times. Something like this:
string[] properties = path.Split('.');
var parameter = Expression.Parameter(typeof(T), "x");
var lhs = parameter;
foreach (var property in properties)
{
lhs = Expression.Property(lhs, property);
}
// I've assumed that the target is a string, given the question. If that's
// not the case, look at Marc's answer.
var rhs = Expression.Constant(targetValue, typeof(string));
var predicate = Expression.Equals(lhs, rhs);
var lambda = Expression.Lambda<Func<T, bool>>(predicate, parameter);

Categories