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

时间:2011-06-16 09:20:59

标签: c# entity-framework-4 localization expression expression-trees

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

为实现这一目标,我想从Entity Framework重写DbExpression CommandTrees。我认为这些trees是用于构建跨数据库插入/更新/选择查询的新常见.NET方式。但现在System.Data.MetadataSystem.Data.Common.CommandTrees中的所有相关构造函数/工厂都在{ {1}}是内部!! (在msdn中公开,例如:DbExpressionBuilder)。

有没有人有想法在有或没有查询树重写的情况下实现这种查询操作?

我想要的代码:(System.Data.Entity.dll

public class DbProviderServicesWrapper : DbProviderServices



更新

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

Multilanguage

3 个答案:

答案 0 :(得分:5)

在.net中,您有resx文件来处理本地化。请参阅:What are the benefits of resource(.resx) files?

您的方法存在一些问题:

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

我知道这不是您问题的直接答案,但我认为您应该查看resx文件。

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

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

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

答案 1 :(得分: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);
  }
}

然后在执行查询之前:

var visitor = new MemberVisitor();
visitor.Visit(query);

同样,如果您不再对数据库进行任何控制,这只是一个好主意。

根据您的具体情况,此解决方案可能对您不切实际,但使用表达式重写查询绝对是可能的。

这比修改Entity Framework生成实际SQL查询的方式要高得多。这确实对你隐瞒了,可能是有充分理由的。相反,您只需修改描述查询的表达式树,让Entity Framework担心将其转换为SQL。

答案 2 :(得分:1)

相反,我会再提出一个设计......

Products
   ProductID 
   ProductName
   Price
   Description
   ParentID (Nullable, FK on ProductID)
   LangCode

现在在这种情况下,你有,

1, Milk, $1 , EnglishDesc  , NULL, en-us 
2. M*^*, ^*&, OtherLangDesc, 1   , @$#$$

您的记录2实际上是LanguageCode标识的不同语言的整个产品的另一种语言描述。

这样你只能管理一个表,编写一些基于Generics或基于反射的查询解决方案会容易得多。

// Get Active Products
q = context.Products.Where( x=> x.ParentID == null);

// Get Product's Language Code Description
IQueryable<Product> GetProductDesc(int productID, string langCode){
    return context.Products.Where( x=>x.ParentID == productID &&
              x.LangCode == langCode);
}

您可以按照以下方式创建界面

interface IMultiLangObject{
    int? ParentID {get;set;}
    string LangCode {get;set;}
}

您可以根据此编写通用解决方案。