I'm not sure if I'm asking this question correctly, or in an understandable way, but here it goes:
I'm trying to figure out a dynamic way to set a value within a select from a database context. I'm using something I call a CodeTableValuePOCO in over a hundred places throughout my code, and I don't want to specify the whole expression every time I need it (especially the syntax for finding the CodeName
value). So, I tried with an expression like this, to generate it dynamically.
internal static Expression<Func<CodeTableValue, CodeTableValuePOCO>> GetCodeTableValueSelectorExpression(int languageId) {
return x => new CodeTableValuePOCO
{
Code = x.Code,
// Check if there are any translations for the code name
CodeName = x.Translations != null
// If there are, check if there is a translation for user's language
? x.Translations.LanguageTranslationTexts.Count(t => t.Language_ID == languageId) > 0
// If there is a translation, take the first for the given language
? x.Translations.LanguageTranslationTexts.FirstOrDefault(t => t.Language_ID == languageId).Text
// Else, default to codeName
: x.CodeName
// Else, default to codeName
: x.CodeName,
CodeTableId = x.CodeTable.CodeTableID,
Id = x.CodeTableValueID,
Key = x.CodeTable.Key,
ParentId = x.ParentID
};
}
But, I can't figure out how to use the above expression in my code. I think it would work if I only was looking for a CodeTableValuePOCO
, but the CodeTableValuePOCO
is embedded in larger selects, like the example below. It's not working, obviously, since the program is expecting a CodeTableValuePOCO, but getting an Expression.
using (MyDbContext db = new MyDbContext()) {
return db.Notifications
.Where(x => x.id == 1)
.Select(x => new NotificationPOCO
{
Id = x.Id,
Message = x.Message,
//This part is, obviously, not working
Type = code.GetCodeTableValueSelectorExpression(2)
})
.ToList();
}
}
There is no natural C# compile time support for using expressions inside other expressions.
You need some expression composition library - for instance, LINQKit. It explains the problem and addresses it with custom Invoke
and AsExpandable
extension methods. The solution in your case is something like this (after installing the package):
using LinqKit;
using (MyDbContext db = new MyDbContext()) {
var codeTableValueSelector = GetCodeTableValueSelectorExpression(2);
return db.Notifications.AsExpandable()
.Where(x => x.id = 1)
.Select(x => new NotificationPOCO
{
Id = x.Id,
Message = x.Message,
Type = codeTableValueSelector.Invoke(x) // or x.CodeTable? not sure from the sample code
})
.ToList();
}