实体框架中内容的国际化

2024-01-02

我不断遇到 i18n 要求,其中我的数据(而不是 UI)需要国际化。

public class FooEntity
{
  public long Id { get; set; }
  public string Code { get; set; } // Some values might not need i18n
  public string Name { get; set } // but e.g. this needs internationalized
  public string Description { get; set; } // and this too
}

我可以使用哪些方法?

我尝试过的一些事情:-

1)在数据库中存储资源密钥

public class FooEntity
{
  ...
  public string NameKey { get; set; }
  public string DescriptionKey { get; set; }
}
  • 优点:无需复杂的查询即可获取翻译的实体。System.Globalization为您处理后备。
  • 缺点:管理员用户无法轻松管理翻译(每当我需要时都必须部署资源文件)Foo的变化)。

2)使用LocalizableString实体类型

public class FooEntity
{
  ...

  public int NameId { get; set; }
  public virtual LocalizableString Name { get; set; }

  public int NameId { get; set; }
  public virtual LocalizableString Description { get; set; }
}

public class LocalizableString
{
  public int Id { get; set; }

  public ICollection<LocalizedString> LocalizedStrings { get; set; }
}

public class LocalizedString
{
  public int Id { get; set; }

  public int ParentId { get; set; }
  public virtual LocalizableString Parent { get; set; }

  public int LanguageId { get; set; }
  public virtual Language Language { get; set; }

  public string Value { get; set; }
}

public class Language
{
  public int Id { get; set; }
  public string Name { get; set; }
  public string CultureCode { get; set; }
}
  • 优点:所有本地化字符串都在同一个表中。可以对每个字符串执行验证。
  • 缺点:查询很糟糕。必须为父实体上的每个可本地化字符串包含一次 LocalizedStrings 表。后备是困难的并且涉及广泛的加入。检索时还没有找到避免 N+1 的方法,例如表的数据。

3)使用具有所有不变属性的父实体和包含所有本地化属性的子实体

public class FooEntity
{
  ...
  public ICollection<FooTranslation> Translations { get; set; }
}

public class FooTranslation
{
  public long Id { get; set; }

  public int ParentId { get; set; }
  public virtual FooEntity Parent { get; set; }

  public int LanguageId { get; set; }
  public virtual Language Language { get; set; }

  public string Name { get; set }
  public string Description { get; set; }
}

public class Language
{
  public int Id { get; set; }
  public string Name { get; set; }
  public string CultureCode { get; set; }
}
  • 优点:将实体完整翻译到内存中并不那么困难(但仍然太难!)。
  • 缺点:实体数量加倍。无法处理实体的部分翻译 - 尤其是名称来自的情况es但描述来自es-AR.

我对解决方案有三个要求

  • 用户可以在运行时编辑实体、语言和翻译

  • 用户可以根据 System.Globalization 提供来自回退的缺失字符串的部分翻译

  • 实体可以被带入内存,而不会遇到例如N+1 个问题


为什么不两全其美呢? 有一个 CustomResourceManager 来处理资源加载并选择正确的区域性,并使用 CustomResourceReader 来使用您喜欢的任何后备存储。基本实现可能如下所示,依赖于 Resourceky 的约定,即 Typename_PropertyName_PropertyValue。如果由于某种原因需要更改后备存储的结构(csv/excel/mssql/表结构),您只需更改 ResourceReader 的实现即可。

作为额外的奖励,我还得到了真实/透明的代理。

资源管理器

class MyRM:ResourceManager
{
    readonly Dictionary<CultureInfo, ResourceSet>  sets = new Dictionary<CultureInfo, ResourceSet>();


    public void UnCache(CultureInfo ci)
    {
        sets.Remove(ci):
    }

    protected override ResourceSet InternalGetResourceSet(CultureInfo culture, bool createIfNotExists, bool tryParents)
    {
        ResourceSet set;
        if (!sets.TryGetValue(culture, out set))
        {
            IResourceReader rdr = new MyRR(culture);
            set = new ResourceSet(rdr);
            sets.Add(culture,set);
        }
        return set; 
    }

    // sets Localized values on properties
    public T GetEntity<T>(T obj)
    {
        var entityType = typeof(T);
        foreach (var prop in entityType.GetProperties(
                    BindingFlags.Instance   
                    | BindingFlags.Public)
            .Where(p => p.PropertyType == typeof(string) 
                && p.CanWrite 
                && p.CanRead))
        {
            // FooEntity_Name_(content of Name field)
            var key = String.Format("{0}_{1}_{2}", 
                entityType.Name, 
                prop.Name, 
                prop.GetValue(obj,null));

            var val = GetString(key);
            // only set if a value was found
            if (!String.IsNullOrEmpty(val))
            {
                prop.SetValue(obj, val, null);
            }
        }
        return obj;
    }
}

资源阅读器

class MyRR:IResourceReader
{
    private readonly Dictionary<string, string> _dict;

    public MyRR(CultureInfo ci)
    {
        _dict = new Dictionary<string, string>();
        // get from some storage (here a hardcoded Dictionary)
        // You have to be able to deliver a IDictionaryEnumerator
        switch (ci.Name)
        {
            case "nl-NL":
                _dict.Add("FooEntity_Name_Dutch", "nederlands");
                _dict.Add("FooEntity_Name_German", "duits");
                break;
            case "en-US":
                _dict.Add("FooEntity_Name_Dutch", "The Netherlands");
                break;
            case "en":
                _dict.Add("FooEntity_Name_Dutch", "undutchables");
                _dict.Add("FooEntity_Name_German", "german");
                break;
            case "": // invariant
                _dict.Add("FooEntity_Name_Dutch", "dutch");
                _dict.Add("FooEntity_Name_German", "german?");
                break;
            default:
                Trace.WriteLine(ci.Name+" has no resources");
                break;
        }

    }

    public System.Collections.IDictionaryEnumerator GetEnumerator()
    {
        return _dict.GetEnumerator();
    }
    // left out not implemented interface members
  }

Usage

var rm = new MyRM(); 

var f = new FooEntity();
f.Name = "Dutch";
var fl = rm.GetEntity(f);
Console.WriteLine(f.Name);

Thread.CurrentThread.CurrentUICulture = new CultureInfo("nl-NL");

f.Name = "Dutch";
var dl = rm.GetEntity(f);
Console.WriteLine(f.Name);

真实代理

public class Localizer<T>: RealProxy
{
    MyRM rm = new MyRM();
    private T obj; 

    public Localizer(T o)
        : base(typeof(T))
    {
        obj = o;
    }

    public override IMessage Invoke(IMessage msg)
    {
        var meth = msg.Properties["__MethodName"].ToString();
        var bf = BindingFlags.Public | BindingFlags.Instance ;
        if (meth.StartsWith("set_"))
        {
            meth = meth.Substring(4);
            bf |= BindingFlags.SetProperty;
        }
        if (meth.StartsWith("get_"))
        {
           // get the value...
            meth = meth.Substring(4);
            var key = String.Format("{0}_{1}_{2}",
                                    typeof (T).Name,
                                    meth,
                                    typeof (T).GetProperty(meth, BindingFlags.Public | BindingFlags.Instance
        |BindingFlags.GetProperty).
        GetValue(obj, null));
            // but use it for a localized lookup (rm is the ResourceManager)
            var val = rm.GetString(key);
            // return the localized value
            return new ReturnMessage(val, null, 0, null, null);
        }
        var args = new object[0];
        if (msg.Properties["__Args"] != null)
        {
            args = (object[]) msg.Properties["__Args"];
        }
        var res = typeof (T).InvokeMember(meth, 
            bf
            , null, obj, args);
        return new ReturnMessage(res, null, 0, null, null);
    }
}

真实/透明代理使用

 var f = new FooEntity();
 f.Name = "Dutch";
 var l = new Localizer<FooEntity>(f);
 var fp = (FooEntity) l.GetTransparentProxy();
 fp.Name = "Dutch"; // notice you can use the proxy as is,
                    // it updates the actual FooEntity
 var localizedValue = fp.Name;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

实体框架中内容的国际化 的相关文章

  • 在 ASP.NET 中创建自定义文化

    我想在 App GlobalResources 文件夹中创建一个名为 shopping en sg resx 的新加坡英语 en sg 资源文件 我在编译过程中遇到错误 错误 1 命名空间 资源 已经包含了一个定义 购物 c WINDOWS
  • 如何让实体框架初始化新创建的实体上的集合?

    我正在尝试用一些测试数据来种子我的数据库IDatabaseIntialiser像这样 protected override void Seed BlogDataContext context
  • UITextInputMode currentInputMode 已弃用。建议更换?

    在我们的应用程序中 我们想检测当前的键盘语言 例如 如果用户在 设置 gt 常规 gt 键盘 gt 键盘 下设置了多种语言键盘 我们想知道他们正在输入什么语言 并在发生变化时从 NSNotificationCenter 收到通知 void
  • 使用 DbMigrationsConfiguration 将ExecutionStrategy 设置为 SqlAzureExecutionStrategy?

    我今天看到一篇关于实现 SqlAzureExecutionStrategy 的帖子 http romiller com tag sqlazureexecutionstrategy http romiller com tag sqlazure
  • Code First - 实体框架 - 如何公开外键

    我有以下数据对象 public class Customer System Data Entity ModelConfiguration EntityTypeConfiguration
  • 使用经度和纬度查找给定距离内的所有附近客户

    我有一个包含客户经度和纬度的数据库 我有一个搜索表单 用户将在其中输入日志 纬度 距离下拉列表包含 50 英里 100 英里 当用户单击搜索时 我想编写一个 linq 查询从数据库中获取此距离半径内的所有客户 如何使用 C 和 linq 来
  • 为什么 DbSet 不是协变的?

    我有一个工厂函数来返回DbSet Of IItemType 实际的返回类型始终是一个实现IItemType 例如DbSet Of CategoryType 我认为泛型支持协方差 并且此方法可以正常工作 但是当我尝试运行代码时出现异常 无法转
  • Dynamic Linq 的执行延迟 IQueryable

    我在用动态链接 https www nuget org packages System Linq Dynamic执行一些查询 抱歉 但这是我唯一的选择 结果 我得到了IQueryable而不是IQueryable
  • Web API 的 ASP.NET MVC Core 控制器 PATCH 方法

    给定一个数据库表 Person 包含 3 列 Id 名字和姓氏 使用真实的 DbContext 时 ASP NET Core Web API MVC 控制器方法 PATCH 仅修改姓氏 看起来如何 我根本不知道如何实现它 并且找不到相关教程
  • 如何使用 poedit 解析 Timber(树枝)模板并检测要翻译的引用字符串

    我想用 poedit 解析 Timber 的树枝模板 并且需要翻译引用的内容 问题是我找不到不跳过引用内容的解析器 Example
  • 如何使用 LINQ to Entities 调用带返回值的 Oracle 函数?

    我正在开发一个从 Oracle 11g 数据库访问数据的应用程序 我使用的是 EF4 并且使用 LINQ 访问数据 我遇到过一个场景 我需要调用存储在包中的函数 这个函数也有一个返回值 我已将此函数添加到实体数据模型中 但无法对其执行 添加
  • 实体框架中的批量插入

    我使用批量插入插入大量记录 例如 20K 当我仅插入一个实体时 它会正常工作 但是 当我用来插入多个实体 例如一对多 时 它将仅插入父实体 而不会插入子实体 我的实体和代码 Customer cs public class Customer
  • 实体框架 - 外键上的双向一对一关系

    我有两个实体 例如 Hat 和 Owner Owner Hat 0 1 1 ID ID Name Size HatId OwnerId 每个主人都有他的帽子 有些帽子没有主人 我创建了模型 public class Owner Key pu
  • 将 F# 类型保存到数据库

    A lot http gorodinski com blog 2013 02 17 domain driven design with fsharp and eventstore f 文章数推荐 http fsharpforfunandpr
  • Entity Framework 6(代码优先)实体版本控制和审计

    我正在考虑将 Entity Framework 6 1 1 与 SQL Server 2008 R2 一起使用 目前 我正在使用代码优先的 EF 功能创建模型和数据库 我的基本用例是创建一个特定实体的所有更改的日志 ID是关键栏 以帮助审核
  • 实体框架 4 DB 优先依赖注入?

    我更喜欢创建自己的数据库 设置索引 唯一约束等 使用 edmx 实体框架设计器 从数据库生成域模型是轻而易举的事 现在我有兴趣使用依赖注入来设置一些存储库 我查看了 StackOverflow 上的一些文章和帖子 似乎重点关注代码优先方法
  • 在c#中映射两个类

    我有两节课 public class foo1 public int id public string image link public string sale price and public class foo2 public int
  • 为什么 EF Core 使用此存储过程总是返回 -1?

    我正在尝试对本地 2016 DB 使用 EF Core 最新版本 并且我得到 1每次都回来 我不知道我做错了什么 我知道它正在到达数据库 我查了一下 int returnCode dbContext Database ExecuteSqlC
  • 使用内存中的单元测试 .ToListAsync()

    下面是由于内存数据库集不支持 ToListAsync 而在 ShouldNotThrow 上失败的测试 我没有方便的确切措辞 但你明白了 如果它很重要 我正在尝试模拟实体框架版本提供的数据库集 6 1 3 TestFixture publi
  • 实体框架中的“it”是什么

    如果以前有人问过这个问题 请原谅我 但我的任何搜索中都没有出现 它 我有两个数据库表 Person 和 Employee 对每个类型的表进行建模 例如 Employee is a Person 在我的 edmx 设计器中 我定义了一个实体

随机推荐

  • 未设置 vs. = NULL [重复]

    这个问题在这里已经有答案了 可能的重复 使用 PHP 释放内存哪个更好 unset 或 var null https stackoverflow com questions 584960 whats better at freeing me
  • ExtJS 图表的性能比 FusionCharts 更好吗?

    我们正在考虑在应用程序中用 ExtJS 图表替换 FusionCharts 因为 我们已经在整个 UI 中使用了 ExtJS 如果能够消除另一个商业第三方依赖项和 API 的开销和费用 那就太好了 我们希望能够在无 Flash 的移动设备上
  • 如何在 Ruby on Rails 中覆盖 Materialise CSS?

    我一直在互联网上浏览一些关于 Rails 中的 Materialise 的帖子 但是这个领域似乎非常模糊 我目前正在使用 Materialize sass gem 我没有找到很多有用的帖子 我决定来这里 这是我的页面代码pages disc
  • ggplot2 在箱线图顶部添加文本

    我有一个正在绘制的数据ggplot2作为箱线图 看起来像 gt head varf sID variable value 1 SP SA036 SA040 CM0001 0 492537313 2 SP SA036 SA040 CM0001
  • jQuery 加载动态元素

    我正在尝试对动态添加到页面上某些容器的元素进行一些条件操作 但我错过了一个事件 假设我有一个容器 div div 我可以轻松地将事件处理程序绑定到所有新元素的单击函数 使用 container on click sub element fu
  • Siri 无法在现有项目中运行

    我必须使用 Siri 通过我的应用程序发起 VoIP 呼叫 它在演示项目中工作 但当我将意图扩展添加到现有项目中时 Siri 不再工作 在系统设置中 我的应用程序未显示在应用程序支持部分中 Plist配置如下 另请参阅扩展的 plist 配
  • hashmap的负载因子和容量

    如何找到hashmap当前的负载因子和容量 Map m new HashMap 10 1 but after lots of works Here how to get current values 您不应该能够获得负载系数和容量 它们是
  • 为什么Java的“受保护”比默认的受保护要少? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 如何禁用 React Material UI 自动完成表单中的 ENTER 键

    我在 React 组件中有一个 Material UI 自动完成表单 它工作完美 除了 ENTER 键当前正在清除输入字段 我只是想要输入字段not当用户按 ENTER 键时被清除 我搜索了 Stackoverflow 上的所有类似问题 没
  • 返回最新“条纹”数据的行

    给出一个包含以下数据的简单表格 id result played 7 L 2012 01 07 6 L 2012 01 06 5 L 2012 01 05 4 W 2012 01 04 3 W 2012 01 03 2 L 2012 01
  • scipy.integrate.solve_ivp 不清楚如何求解形式 0=F(t, y(t), y'(t)) 的隐式 ODE

    目前 我确实使用assimulos 求解器套件 https jmodelica org assimulo tutorial imp html求解 0 F t y t y t 形式的隐式微分方程 我想使用本机 scipy 安装附带的求解器 并
  • Android页面卷曲动画

    有没有简单的方法来做Curl翻页动画 卷曲动画是页面翻转的动画 包括上面的页面滚动和下面的页面阴影 一次显示两页的 画廊 就像一本书一样 的推荐方法是什么 Is it 让适配器一次显示两个图像的线性布局 它不会让我像书一样显示一页翻过另一页
  • 为什么 echo 不返回与没有 echo 相同的结果

    我有以下案例 regex OK space alnum alnum text OK AAA BBBBBB aaabbbcccdddfffed asdadadadadadsada OK CCC KKKKKKK some text here O
  • C# 刷新 StreamWriter 和 MemoryStream

    我使用以下代码片段 我不确定是否需要调用Flush方法 一旦StreamWriter 一旦开启MemoryStream converts an xsd object to the corresponding xml string using
  • 如何在 Perl 中运行子命令正确导入环境?

    在从子命令导入环境时 我想将从 bash 脚本导出的所有环境变量添加到哈希中 什么时候program运行后 它将设置一些变量并导出它们 我想将这些变量保存在 Perl 脚本中供以后使用 但是我不想采用子命令中定义的 bash 函数 目前 我
  • 如何从 Java 获取 JanusGraphManagement

    我无法理解如何从使用ConfiguredGraphFactory 创建的图表中获取JanusGraphManagement 实例 我尝试做这样的事情 JanusGraphFactory Builder config JanusGraphFa
  • 更新 Popup.Animated 以播放 gif 直到外部任务完成 (PYSimpleGUI)

    我希望创建一个 UI 在执行另一项任务时显示动画弹出窗口 完成后将退出 我正在使用 PYSimpleGUI 并使用列出的示例here https github com PySimpleGUI PySimpleGUI blob master
  • 自定义注释不适用于 spring Bean

    我创建了新的自定义注释 MyCustomAnnotation Target ElementType METHOD ElementType TYPE ElementType FIELD Retention RUNTIME public int
  • com4j 与 jacob 从 Java 调用 COM 方法

    我维护一个遗留的 Java 应用程序 它使用Jacob http danadler com jacob 或Java COM Bridge 通过MS VBA和MS Word的COM接口进行调用 我一直在看com4j https com4j d
  • 实体框架中内容的国际化

    我不断遇到 i18n 要求 其中我的数据 而不是 UI 需要国际化 public class FooEntity public long Id get set public string Code get set Some values m