EntityFramework查询操作,db提供程序包装,db表达式树

ben*_*asd 14 c# expression localization expression-trees entity-framework-4

我正在尝试为Entity Framework实现数据本地化逻辑.因此,如果例如查询选择Title属性,则在幕后它应该引用列Title_enGBTitle_deCH取决于当前用户文化.

为此,我想从Entity Framework重写DbExpression CommandTrees.我以为这些是建立跨数据库插入/更新/ select查询.但现在所有相关的构造函数/在命名空间中的工厂新的通用.NET的方式System.Data.MetadataSystem.Data.Common.CommandTreesSystem.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)



更新

在一个表上有两个标题列并不酷,但在第一步中更容易实现.稍后我将使用本地化字段加入另一个表,因此主表将只包含不变数据.

多语言

Shi*_*iji 5

在.net中,您有resx文件来处理本地化.请参阅:资源(.resx)文件有哪些好处?

您的方法存在一些问题:

  • 添加额外的语言需要更改数据库
  • 数据库中的数据流量超出了要求

我知道这不是你问题的直接答案,但我认为你应该看一下resx文件.

如果必须将其存储在数据库中,则可以重新设计数据库:

  • 表1:id,文本
  • 表2:id,Table1_id,language_code,text

这样,新语言不需要更改数据库,EF代码变得更加简单.


Jul*_*anR 5

我同意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.