我正在尝试为Entity Framework实现数据本地化逻辑。因此,如果查询选择Title
属性,则在幕后它应引用列Title_enGB
或Title_deCH
,具体取决于当前的用户文化。
为实现这一目标,我想从Entity Framework重写DbExpression CommandTrees。我认为这些trees是用于构建跨数据库插入/更新/选择查询的新常见.NET方式。但现在System.Data.Metadata
和System.Data.Common.CommandTrees
中的所有相关构造函数/工厂都在{ {1}}是内部!! (在msdn中公开,例如:DbExpressionBuilder
)。
有没有人有想法在有或没有查询树重写的情况下实现这种查询操作?
我想要的代码:(System.Data.Entity.dll
)
public class DbProviderServicesWrapper : DbProviderServices
在一个表上有两个标题列并不酷,但在第一步中更容易实现。稍后我将使用本地化字段加入另一个表,因此主表将只包含不变数据。
答案 0 :(得分:5)
在.net中,您有resx文件来处理本地化。请参阅:What are the benefits of resource(.resx) files?
您的方法存在一些问题:
我知道这不是您问题的直接答案,但我认为您应该查看resx文件。
如果必须将其存储在数据库中,则可以重新设计数据库:
这样一种新语言不需要更改数据库,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;}
}
您可以根据此编写通用解决方案。