如何对 Entity Framework select 子句中的值使用动态表达式
How to use a dynamic expression for a value in an Entity Framework select clause
我不确定我问这个问题是否正确,或者以一种可以理解的方式,但这里是:
我正在尝试找出一种动态方法来从数据库上下文中设置 select 中的值。我在我的代码中的一百多个地方使用了我称之为 CodeTableValuePOCO 的东西,我不想每次需要时都指定整个表达式(尤其是用于查找 CodeName
值的语法)。所以,我尝试使用这样的表达式来动态生成它。
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
};
}
但是,我不知道如何在我的代码中使用上面的表达式。我认为如果我只是在寻找 CodeTableValuePOCO
,但 CodeTableValuePOCO
嵌入较大的 select 中,如下例所示。显然,它不起作用,因为程序需要一个 CodeTableValuePOCO,但得到一个表达式。
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();
}
}
没有自然的 C# 编译时支持在其他表达式中使用表达式。
您需要一些表达式组合库 - 例如,LINQKit。它解释了问题并使用自定义 Invoke
和 AsExpandable
扩展方法解决了这个问题。你的解决方案是这样的(安装包后):
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();
}
我不确定我问这个问题是否正确,或者以一种可以理解的方式,但这里是:
我正在尝试找出一种动态方法来从数据库上下文中设置 select 中的值。我在我的代码中的一百多个地方使用了我称之为 CodeTableValuePOCO 的东西,我不想每次需要时都指定整个表达式(尤其是用于查找 CodeName
值的语法)。所以,我尝试使用这样的表达式来动态生成它。
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
};
}
但是,我不知道如何在我的代码中使用上面的表达式。我认为如果我只是在寻找 CodeTableValuePOCO
,但 CodeTableValuePOCO
嵌入较大的 select 中,如下例所示。显然,它不起作用,因为程序需要一个 CodeTableValuePOCO,但得到一个表达式。
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();
}
}
没有自然的 C# 编译时支持在其他表达式中使用表达式。
您需要一些表达式组合库 - 例如,LINQKit。它解释了问题并使用自定义 Invoke
和 AsExpandable
扩展方法解决了这个问题。你的解决方案是这样的(安装包后):
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();
}