ben*_*asd 14 c# expression localization expression-trees entity-framework-4
我正在尝试为Entity Framework实现数据本地化逻辑.因此,如果例如查询选择Title属性,则在幕后它应该引用列Title_enGB或Title_deCH取决于当前用户文化.
为此,我想从Entity Framework重写DbExpression CommandTrees.我以为这些树是建立跨数据库插入/更新/ select查询.但现在所有相关的构造函数/在命名空间中的工厂新的通用.NET的方式System.Data.Metadata和System.Data.Common.CommandTrees在System.Data.Entity.dll都内!(在msdn中公开记录,如:)DbExpressionBuilder.
有没有人有想法实现这个查询操作有或没有查询树重写?
我想要的代码:( public class DbProviderServicesWrapper : DbProviderServices)
/// <summary>
/// Creates a command definition object for the specified provider manifest and command tree.
/// </summary>
/// <param name="providerManifest">Provider manifest previously retrieved from the store provider.</param>
/// <param name="commandTree">Command tree for the statement.</param>
/// <returns>
/// An exectable command definition object.
/// </returns>
protected override DbCommandDefinition CreateDbCommandDefinition(DbProviderManifest providerManifest, DbCommandTree commandTree)
{
var originalCommandTree = commandTree as DbQueryCommandTree;
if (originalCommandTree != null)
{
var expression = new MyCustomQueryRewriter(originalTree.MetadataWorkspace).Visit(originalCommandTree.Query);
commandTree = DbQueryCommandTree.FromValidExpression(originalCommandTree.MetadataWorkspace, originalCommandTree.DataSpace, expression);
}
// TODO: UpdateCommand/InsertCommand
var inner = this.Inner.CreateCommandDefinition(providerManifest, commandTree);
var def = new DbCommandDefinitionWrapper(inner, (c, cd) => new DbCommandWrapper(c));
return def;
}
Run Code Online (Sandbox Code Playgroud)
在一个表上有两个标题列并不酷,但在第一步中更容易实现.稍后我将使用本地化字段加入另一个表,因此主表将只包含不变数据.

在.net中,您有resx文件来处理本地化.请参阅:资源(.resx)文件有哪些好处?
您的方法存在一些问题:
我知道这不是你问题的直接答案,但我认为你应该看一下resx文件.
如果必须将其存储在数据库中,则可以重新设计数据库:
这样,新语言不需要更改数据库,EF代码变得更加简单.
我同意Shiraz的答案,如果您仍然能够更改设计,那么这不应该是您想要的,但我会假设这是您要转换为Entity Framework的现有应用程序.
如果是这样,那么Title_enGB/etc列是否映射到EDMX文件/ POCO中是很重要的.如果是,我想这是可能的.你在这里可以做的是使用访问MemberExpressions的Expression访问者,检查他们是否访问名为"Title"的属性(你可以创建一个需要像这样对待的属性的白名单),然后返回一个新的MemberExpression而不是访问Title_enGB如果登录用户具有该语言集.
一个简单的例子:
public class MemberVisitor : ExpressionVisitor
{
protected override Expression VisitMember(MemberExpression node)
{
if(node.Member.Name == "Title")
{
return Expression.Property(node.Expression, "Title_" + User.LanguageCode)
}
return base.VisitMember(node);
}
}
Run Code Online (Sandbox Code Playgroud)
然后在执行查询之前:
var visitor = new MemberVisitor();
visitor.Visit(query);
Run Code Online (Sandbox Code Playgroud)
同样,如果您不再对数据库有任何控制,这只是一个好主意.
根据您的具体情况,此解决方案对您来说可能是实用的,也可能不实用,但使用表达式重写查询绝对是可能的.
它比修改实体框架生成实际SQL查询的方式更高级别的解决方案.这确实对你隐瞒了,可能是有充分理由的.相反,您只需修改描述查询的表达式树,让Entity Framework担心将其转换为SQL.