'System.NotSupportedException: Member Month of type System.DateTimeOffset in the expression tree {ExampleModel}{EndTime}.Month cannot be translated
I'm trying to do this method:
Task<Result<IQueryable<ExampleViewModel>>> Handle(ExampleQuery request)
{
return Result.Success(_repository.Get()
.SelectMany(x => x.ExampleModel)
.Select(y => new ExampleViewModel(
y.EndTime.Month,
y.EndTime,
y.IsOK,
y.Name)));
}
but this generated the error bellow:
System.NotSupportedException: Member Month of type System.DateTimeOffset in the expression tree {ExampleModel}{EndTime}.Month cannot be translated. The unsupported member type is located on type 'ViewModels.ExampleViewModel'. Path: $. ---> System.NotSupportedException: Member Month of type System.DateTimeOffset in the expression tree {ExampleModel}{EndTime}.Month cannot be translated.
but if I break the code creating a list before:
Task<Result<IQueryable<ExampleViewModel>>> Handle(ExampleQuery request)
{
var listModel = _repository.Get()
.SelectMany(x => x.ExampleModel).ToList();
return Result.Success(listModel
.Select(y => new ExampleViewModel(
y.EndTime.Month,
y.EndTime,
y.IsOK,
y.Name)).AsQueryable());
}
and the error disappears. Everything works fine:
[
{
"month": 3,
"date": "2022-03-30T15:59:14.6422341-03:00",
"IsOK": false,
"Name": "example name"
}
]
my Model:
public class ExampleModel
{
public ExampleModel(string name, bool isOK, DateTimeOffset startTime, DateTimeOffset endTime)
{
Name = name;
IsOK = isOK;
StartTime = startTime;
EndTime = endTime;
}
public string Name { get; protected set; }
public bool IsOK{ get; protected set; }
public DateTimeOffset StartTime { get; protected set; }
public DateTimeOffset EndTime { get; protected set; }
}
my ViewModel
public class ExampleViewModel
{
public ExampleViewModel(int month, DateTimeOffset date, bool isOK, string name)
{
Month = month;
Date = date;
IsOK = isOK;
Name = name;
}
public int Month { get; set; }
public DateTimeOffset Date { get; set; }
public bool IsOK { get; set; }
public string Name { get; set; }
}
this is how the collection looks like (I'm not the creator and don't have permission to change any)
{
"_id": "6244a72f902597a15d941b04",
"_t": "Examples",
"CreatedAt": [
{
"$numberLong": "637842632155392881"
},
0 ],
"Example": [
{
"Name": "example name",
"IsOK": false,
"StartTime": [
{
"$numberLong": "637842526150485990"
},
-180 ],
"EndTime": [
{
"$numberLong": "637842527546422341"
},
-180 ]
}
]
I guess it's a problem with MongoDB.Driver, but maybe there is a way to run this without use a list.
[Edit]
after thinking a little more, this was my solution:
I removed the month from my Viewmodel constructor:
Task<Result<IQueryable<ExampleViewModel>>> Handle(ExampleQuery request)
{
return Result.Success(_repository.Get()
.SelectMany(x => x.ExampleModel)
.Select(y => new ExampleViewModel(
y.EndTime,
y.Passed,
y.Name)));
}
and now the class have all the control over the property:
public ExampleViewModel(DateTimeOffset date, bool passed, string name)
{
Date = date;
IsOK = isOK;
Name = name;
}
public int Month
{
get { return Date.Month; }
}
public DateTimeOffset Date { get; private set; }
public bool IsOK { get; private set; }
public string Name { get; private set; }
Solution 1:[1]
LINQ is an overarching technology but, when executed, LINQ requires a provider to translate your LINQ code into something that will work against the data source in use. If you're using a LINQ provider against a database then the provider will be translating your LINQ code into SQL, so you can only use what that provider can translate. Obviously your provider for your database cannot translate that Month property to a SQL function so it's not allowed.
By calling ToList, you execute the database query first and create a List(Of ExampleModel) locally, then you use the LINQ to Objects provider to get the Month property of the Date it contains. That is done in your app, not in the database, so there's no translation required, so there's no issue.
In short, if there is no function in MongoDB to get the month from a date or there is no translation to that function in the LINQ provider then you have no choice but to do exactly what you're doing, i.e. realise the database query first and then pull out just the parts you need. If there is such a function but no such translation then you could create a view or stored procedure in the database that uses that function and then write LINQ code to query that view or stored procedure.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | user18387401 |
