C# 谁应该创建业务对象?

C# 谁应该创建业务对象?,c#,data-access-layer,domain-model,C#,Data Access Layer,Domain Model,因为业务/域对象应该不知道它们的持久性,所以它们显然不能包含从数据库加载数据以初始化自身的代码 另一方面,并非所有业务对象的属性都有公共设置器来帮助封装并避免将它们设置为无效值 这意味着,当业务对象的数据从数据库中获取时,没有其他类可以完全初始化业务对象 由于以上所有内容都是常见的最佳实践,因此必须找到解决该问题的方法那么谁应该负责构建业务对象并用数据库中的数据填充它们呢? 注意:我想到的唯一选择是将所有属性添加到构造函数中,这在我看来是非常不切实际的。这可能会因为术语而变得复杂-同一事物通常可

因为业务/域对象应该不知道它们的持久性,所以它们显然不能包含从数据库加载数据以初始化自身的代码

另一方面,并非所有业务对象的属性都有公共设置器来帮助封装并避免将它们设置为无效值

这意味着,当业务对象的数据从数据库中获取时,没有其他类可以完全初始化业务对象

由于以上所有内容都是常见的最佳实践,因此必须找到解决该问题的方法那么谁应该负责构建业务对象并用数据库中的数据填充它们呢?


注意:我想到的唯一选择是将所有属性添加到构造函数中,这在我看来是非常不切实际的。

这可能会因为术语而变得复杂-同一事物通常可能有多个名称,或者一个模式可能是其他离散模式的合并。希望这个(非常简短的)答案对你有意义

通常,您会有一个数据层(DAL)或“数据服务”,其工作是与数据存储进行通信(或者,它可以与存储库层或ORM进行通信)

根据您的设置,负责创建数据实体(“业务对象”)的层可能会有所不同。ORM(如实体框架)可以返回数据实体,但在它们进入应用程序的其余部分之前,通常需要将它们更改为更不可知的内容,因此DAL(或特定数据“服务”)的工作就是将它们从EF对象映射到常规数据实体


或者,存储库层可以创建用于查询底层数据存储的实体。

存储库应该能够根据数据层提供的信息创建业务对象。逻辑是,由于存储库应该以对用户隐藏实现的方式持久化您传入的对象,因此它必须能够序列化和反序列化该对象,而无需任何额外信息

如果对象具有私有数据,一种常见的模式是通过构造函数传递私有信息

不需要调用存储库就可以创建新对象。通常通过公共构造函数

例如:


解决这个问题的办法很少。但两者都不是“完美的”

  • 使用反射设置私有字段或属性。大多数orm都使用这种解决方案。问题可能是当ORM设置属性时,该属性上有一些逻辑,导致实体的非逻辑状态(我被这烧坏了好几次)
  • 将“数据持久性”抽象为键/值映射。通过这种方式,实体可以自己持久化,并且仍然独立于特定的持久化技术。但是您仍然需要显式地编写代码
  • 构建器模式。具有具有相同属性的单独类,该类可以访问实体的私有字段,但仅用于构造。主要缺点是每个实体都需要一个生成器
  • 创建一个DTO,它反映实体的状态,但不反映实体的行为。然后,实体可以读取/创建此数据以加载或保存自身。与上述相同的缺点

  • 我个人看不出你的问题有什么好的答案,除非你能自动完成前面的一个解决方案。要么通过代码生成,要么通过语言支持。例如,对“构建器模式”提供语言支持会有很大帮助。

    通常,您在
    服务
    层中创建业务对象(即
    用户服务
    创建
    用户
    bean),然后它应该将其发送到存储库(即
    用户存储库
    )以将其持久化。要查找现有bean,请调用服务来调用存储库-存储库创建bean并从数据库中填充它阅读您的评论我认为您的问题来自您对业务对象“应该”是什么的想法。在我看来,您的方法中可能有带有业务逻辑的经典OO风格对象。然而,存储库来自一个更晚的时代,在这个时代,逻辑将被放置在一个服务中,对象将只包含数据。混合这些概念并非不可能,但例如,您当前如何创建对象?@Ewan贫乏的域模型被认为是一种反模式。它远远不是“现代的”。“存储库”与对象建模一样古老。@Ewan:我目前正在决定如何根据最佳实践创建对象。因此,我读了很多关于业务对象“应该”的内容。问题是在这个问题上没有真正的一致意见,只是有很多不同的意见……我的问题恰恰相反。如何使用私有设置器或不使用设置器获取对象?很抱歉,我试图将代码最小化。更新这基本上意味着您只需将所有属性添加到构造函数?我个人会添加公共setter,但因为这不在范围内。是的,构造函数应该能够构造对象谢谢你的回答。我知道DAL,ORMs等等。问题是,好的业务对象具有只读属性,并且不允许出现无效状态,如果您只是通过ORM一个接一个地设置属性,就会出现无效状态。你是如何处理这些案件的?我想你把一些事情弄糊涂了。。。没有“好的业务对象具有只读属性”这样的东西——您需要在某个阶段更改这些属性的值,这些对象在使用MVVM时对您毫无用处。你想的是使对象不可变,这又是一种不同的哲学。我知道对于好的业务对象是什么样子有很多不同的观点,我不是说使所有属性都是只读的。仅限不应直接设置的属性(例如主键)。我已经公开了所有的财产
    public class Model {
            public String Id {get;set;}
            public String Colour { get; set; }
    
            public Model(String id, String colour)
            {
                this.Id = id;
                this.Colour = colour;
            }
        }
    
        public interface IRepository
        {
            void Add(Model item);
            Model Get(string id);
        }
    
        public class RepositorySql : IRepository
        {
            private string constr;
            public RepositorySql(string connstr)
            {
                this.constr = connstr;
    
            }
            public void Add(Model item)
            {
                using (SqlConnection conn = new SqlConnection(constr))
                {
                    conn.Open();
                    using (SqlCommand cmd = new SqlCommand("insert into table (userid,colour) values (@userid,@colour)", conn))
                    {
                        cmd.Parameters.AddWithValue("@id", item.Id);
                        cmd.Parameters.AddWithValue("@colour", item.Colour);
                        cmd.ExecuteNonQuery();
                    }
                }
            }
    
    
            public Model Get(string id)
            {
                using (SqlConnection conn = new SqlConnection(constr))
                {
                    conn.Open();
                    using (SqlCommand cmd = new SqlCommand("select * from table where id=@id)", conn))
                    {
                        cmd.Parameters.AddWithValue("@id", item.UserId);
                        SqlDataReader dr  =cmd.ExecuteReader();
    
                        if (dr.Read())
                        {
                            Model i = new Model(dr["id"].ToString(), dr["colour"].ToString());
                            return i;
                        }
                        else
                        {
                            return null;
                        }
                    }
                }
            }
        }