来自名称值对的配置对象

发布于 2024-12-07 20:49:57 字数 1662 浏览 0 评论 0 原文

我正在开发一个需要在数据库中存储和更新配置的网络应用程序。例如,我可能存储用户首选项,如默认颜色、语言、首选日期格式等。

数据库表由名称/值对 (nvarchars) 组成。够简单的。

我正在使用 ORM 来获取这些名称/值字符串对的列表(实际上是 IEnumerable)。我的问题是我需要将这些 IEnumerable 转换为比名称/值字符串更具表现力的东西。也就是说,我想制作一个强类型的配置对象。

理想情况下,我想让这个配置对象不直接依赖于 ORM,但我不确定如何解决这个问题,因为这个对象的初始化和用户首选项的持久性需要经过ORM。

某种设计模式可以拯救?

(这应该不重要,但我正在使用 C# 和实体框架。)


编辑:

假设我的域对象中有以下字段:

public class SettingNameValuePair {
    public string Name {get;set;}
    public string Value {get;set;}
}

public class GlobalSettings {
    public System.Drawing.Color FontColor {get;set;}
    public TimeZoneInfo DefaultTimeZone {get;set;}
    public DateTime DateCreated {get;set;}

    ... constructor ...
    ... validation, other functions ...
}

我可以设置 ORM 来获取和持久化无需太多努力即可设置NameValuePair。但是,如何获取并保留 GlobalSettings?也就是说,在我的应用程序中的某个位置,我想获取全局设置的实例。

using (var context = new ApplicationContext()) {    
    GlobalSettings settings = ???
}

当然,ORM 不知道如何在SettingNameValuePair 和GlobalSettings 之间自动转换。我知道我需要编写一些“管道”代码来生成 GlobalSettings 的强类型属性。

我的问题是:取回由SettingNameValuePair 填充的GlobalSettings 实例的好方法是什么?这里有两个选项肯定是错误的:

1)让 GlobalSettings 的构造函数将数据上下文作为参数。这引入了不良的依赖性并且难以测试。

2)让GlobalSettings的构造函数从数据上下文中获取SettingNameValuePair,如下所示:

using (var context = new ApplicationContext()) {    
    IEnumerable<SettingNameValuePair> nameValuePairs = 
        context.NameValuePairs.ToList();
    GlobalSettings settings = new GlobalSettings(nameValuePairs);
}

这样做的问题是您必须在各处重复此代码。

我感觉有更好的解决方案涉及单例、静态类、代理或工厂方法,但我对这些概念还不太满意。

I am working on a web app that needs to store and update configurations in a database. For example, I might store user preferences like default colors, languages, preferred date formats, etc.

The database table consists of name/value pairs (nvarchars). Simple enough.

I am using an ORM to fetch a list -- actually an IEnumerable -- of these pairs of name/value strings. My problem is that I need to turn these IEnumerable into something that is more expressive than strings of names/values. That is, I want to make a strongly-typed configuration object.

Ideally, I'd like to make it so that this configuration object doesn't have a direct dependency on the ORM, but I'm not sure how to go about this, since the initialization of this object and the persistence of the user preferences needs to go through the ORM.

Some sort of design pattern to the rescue?

(It shouldn't matter, but I'm using C# and Entity Framework.)


EDIT:

Let's say that I have the following fields in my domain objects:

public class SettingNameValuePair {
    public string Name {get;set;}
    public string Value {get;set;}
}

public class GlobalSettings {
    public System.Drawing.Color FontColor {get;set;}
    public TimeZoneInfo DefaultTimeZone {get;set;}
    public DateTime DateCreated {get;set;}

    ... constructor ...
    ... validation, other functions ...
}

I can set up my ORM to fetch and persist SettingNameValuePair without much effort. However, how do I fetch and persist GlobalSettings? That is, somewhere in my application I want to get an instance of my Global Settings.

using (var context = new ApplicationContext()) {    
    GlobalSettings settings = ???
}

The ORM will not know how automatically convert between SettingNameValuePair and GlobalSettings, of course. I know I will need to write some "plumbing" code to produce the strongly-typed properties of GlobalSettings.

My question is: What is a good way to get back an instance of GlobalSettings that is populated by SettingNameValuePair? Here are two options are surely wrong:

1) Have the constructor of GlobalSettings take the data context as an argument. This introduces a bad dependency and is difficult to test.

2) Have the constructor of GlobalSettings take the SettingNameValuePair's from the data context like so:

using (var context = new ApplicationContext()) {    
    IEnumerable<SettingNameValuePair> nameValuePairs = 
        context.NameValuePairs.ToList();
    GlobalSettings settings = new GlobalSettings(nameValuePairs);
}

The problem with this is that you have to repeat this code all over the place.

I get the feeling that there are better solutions that involve Singletons, static classes, Proxies or Factory methods, but I'm not comfortable with these concepts yet.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

ι不睡觉的鱼゛ 2024-12-14 20:49:57

不要在域对象中引用您的 ORM,而是在存储库中实现它,该存储库将利用您的 ORM 或任何数据访问技术(例如数据读取器,因为大多数 orms 将无法在键值对和强类型对象之间映射)。

另外,我不建议在构造函数中为实体(全局设置)提供键值对,因为它与域无关,请将键值对映射到域对象,而是在映射器层(例如您的存储库或 dal)中实现

映射:

在应用层

public GlobalSettings GetUserSettings(User user)
{
  return _globalSettingsRepository.GetGlobalSettings(user);
}

在存储层

public GlobalSettings GetGlobalSettings(User user)
{
  var keyvalue = _context.blablabla();
  var globalSettings = new GlobalSettings { Id = keyvalue["key"], DateCreated = DateTime.Parse(keyvalue["datecreated"]) };
  return globalSettings
}

Don't reference your ORM in your domain object, instead implement it in the repository which will utilize either your ORM or whatever data access techniques (data reader for example as most orms will not be able to map between key value pair and strongly typed objects).

also i dont recommend to give the entity (globalsettings) a key value pair in the constructor as it is not related to domain do map key value pairs to domain object, instead implement the mapping in the mapper layer which is your repository or dal

for example:

In application layer

public GlobalSettings GetUserSettings(User user)
{
  return _globalSettingsRepository.GetGlobalSettings(user);
}

In repository layer

public GlobalSettings GetGlobalSettings(User user)
{
  var keyvalue = _context.blablabla();
  var globalSettings = new GlobalSettings { Id = keyvalue["key"], DateCreated = DateTime.Parse(keyvalue["datecreated"]) };
  return globalSettings
}
捂风挽笑 2024-12-14 20:49:57

我认为没有任何 ORM 可以映射到键值对。事实上,使用 DataReader 来读取这些数据可能会更有效。无论您如何获取数据,您都可以简单地使用配置 KVP 来构建字典,然后使用 用于访问的属性模式。然后,您可以为您知道需要的属性创建强类型访问器。这将允许您将强类型对象用于您了解的属性,同时仍然保持添加属性而不更改代码的灵活性。

I don't think that there is any ORM out there that maps to Key-Value Pairs. In fact, it would probably be more efficient to use a DataReader for this data. However you get the data, you could simply use your configuration KVPs to build a dictionary, then use the Property Pattern for access. You can then create strongly typed accessors for the properties that you know that you will need. This will allow you to use strongly typed objects for the properties you know about, while still maintaining the flexibility to add properties without changing the code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文