【问题标题】:POCO's, ORM and immutability. How to make them work together?POCO、ORM 和不变性。如何让它们协同工作?
【发布时间】:2012-10-29 21:10:25
【问题描述】:

假设我有以下 C# 类,我希望它是不可变的。只能使用参数化的构造函数来设置。

public class InsulineInjection
{
    private InsulineInjection()
    {
        // We don't want to enable a default constructor.
    }

    public InsulineInjection(Millilitre millilitre, DateTime dateTime, string remark)
    {
        this.Remark = remark;
        this.DateTime = dateTime;
        this.Millilitre = millilitre;
    }

    public string Remark { get; private set; }
    public DateTime DateTime { get; private set; }
    public Millilitre Millilitre { get; private set; }
}

现在我想使用 ORM 来创建这个 POCO。但是,据我所知,所有 .NET ORM 都期望属性是可访问的,并且具有能够创建此 POCO 的公共构造函数。所以我不得不把我的 POCO 改成这样:

public class InsulineInjection
{
    public InsulineInjection()
    {
    }

    public InsulineInjection(Millilitre millilitre, DateTime dateTime, string remark)
    {
        this.Remark = remark;
        this.DateTime = dateTime;
        this.Millilitre = millilitre;
    }

    public string Remark { get; set; }
    public DateTime DateTime { get; set; }
    public Millilitre Millilitre { get; set; }
}

然而,这使我的 POCO 再次可变。使用它的人可以在之后简单地更改任何我不想要的属性。

据我所知,我可以通过两种不同的方式解决这个问题:

  1. 编写我自己的数据访问层(或修改一个 orm),以便能够使用我创建的构造函数创建正确的 POCO 实例。
  2. 创建某种映射器。让 ORM 创建简单的 DTO 对象,并在适当的时候使用映射器将 DTO 对象转换为我的 POCO。

我倾向于解决方案 2。有人有如何做到这一点的例子吗?或者有人有比我上面描述的更好的解决方案吗?

【问题讨论】:

  • #2 听起来很有可能。像 automapper 这样的组件可能会派上用场。您的应用程序的哪些客户端/层要求您的类型是不可变的?
  • 为什么你希望你的数据库对象是不可变的?查询会很好,但是您打算如何更新数据库中的值?我和其他人一样喜欢不可变类型,但这似乎是可变类型的合适位置。
  • 这段代码只是一个小爱好项目的示例。它应该代表您可以添加新的注入。但是,一旦添加,就无法再对其进行修改。当然,我可以在 UI 中对其进行编码,但我发现如果在 POCO 中表示此功能,它会更具启发性。

标签: c# orm poco immutability


【解决方案1】:

只要有默认的构造函数和设置器,许多 OR/M 就可以工作(无论它们是否公开,它们都必须存在)

所以这行不通(没有默认构造函数):

public class InsulineInjection
{
    public InsulineInjection(Millilitre millilitre, DateTime dateTime, string remark)
    {
        this.Remark = remark;
        this.DateTime = dateTime;
        _millilitre = millilitre;
    }

    public string Remark { get; set; }
    public DateTime DateTime { get; set; }
    public Millilitre Millilitre { get { return _millilitre; } }
}

或者这个(最后一个属性没有设置器)

public class InsulineInjection
{
    public InsulineInjection(Millilitre millilitre, DateTime dateTime, string remark)
    {
        this.Remark = remark;
        this.DateTime = dateTime;
        _millilitre = millilitre;
    }

    public string Remark { get; set; }
    public DateTime DateTime { get; set; }
    public Millilitre Millilitre { get { return _millilitre; } }
}

虽然这会起作用:

public class InsulineInjection
{
    protected InsulineInjection()
    {
        // works with many OR/Ms
    }

    public InsulineInjection(Millilitre millilitre, DateTime dateTime, string remark)
    {
        this.Remark = remark;
        this.DateTime = dateTime;
        this.Millilitre = millilitre;
    }

    public string Remark { get; private set; }
    public DateTime DateTime { get; private set; }
    public Millilitre Millilitre { get; private set; }
}

【讨论】:

  • 谢谢,我不知道最后一个示例可以使用 OR/M。
  • 是的。但并非所有 ORM 都支持 get-only 属性(即根本没有 setter)
【解决方案2】:

为避免构造函数被自己的代码使用,可以使用Obsolete attribute

[Obsolete("Default constructor only here for the ORM", true)]
public InsulineInjection() {}

如果您实际调用此构造函数,在属性中传递true 将产生编译器错误。

【讨论】:

  • 你还需要有供ORM使用的setter,这是他不想暴露的。
  • 查看其他答案
  • 当您发布问题的答案时,您应该回答问题,而不是依赖其他答案来实际回答问题。如果您只是想在现有答案中添加一些内容,那么您应该对其中一个答案发表评论。
  • 我只是想添加一个有用的提示,但对于评论来说似乎太长了。抱歉,它不符合您的高标准。是否有规则规定您不能在此处添加部分答案?
  • 我认为常识会规定,在发布问题的答案时,您应该实际回答问题。
【解决方案3】:

并非所有 .NET ORM 都需要公共属性访问权限才能写入数据。 NHibernate 支持将数据写入私有字段或设置器。但是,您需要遵循一种允许的字段命名约定,以便它可以从属性名称中推断出字段名称。

Check out NHibernate documentation about property mapping,特别看一下表 5.1。访问策略和表 5.2。命名策略。查看nosetter 访问策略并选择适合您编码风格的命名策略。

【讨论】:

    【解决方案4】:

    此场景由 dapper-dot-net 本地处理。

    您只需要查询字段的顺序和类型来匹配构造函数参数的顺序和类型。因此,对于您的班级,查询将类似于:

    select millilitre, 
        ,dateTime
        ,remark
    from injections
    

    不幸的是,dapper 不知道如何将十进制转换为毫升。

    【讨论】:

      猜你喜欢
      • 2015-11-11
      • 1970-01-01
      • 1970-01-01
      • 2019-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-17
      相关资源
      最近更新 更多