4

假设我有以下 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。有人有如何做到这一点的例子吗?或者有人有比我上面描述的更好的解决方案吗?

4

4 回答 4

5

只要有默认的构造函数和设置器,许多 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; }
}
于 2012-11-09T14:36:28.927 回答
3

为了避免构造函数被你自己的代码使用,你可以使用Obsolete 属性

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

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

于 2012-11-09T14:36:13.550 回答
2

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

查看有关属性映射的 NHibernate 文档,特别是查看表 5.1。访问策略和表 5.2。命名策略。查看nosetter访问策略并选择适合您的编码风格的命名策略。

于 2012-11-09T14:36:05.680 回答
1

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

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

select millilitre, 
    ,dateTime
    ,remark
from injections

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

于 2013-12-19T01:06:12.770 回答