【问题标题】:Repositories in domain driven design领域驱动设计中的存储库
【发布时间】:2014-04-23 19:05:44
【问题描述】:

我几个月来一直在为 DDD 苦苦挣扎,虽然我认为我对一些概念有相当好的想法,但我对实现的工作方式不太有信心,特别是我应该如何从数据库中加载数据.我只在 C# 中工作了六个月(零星地),这于事无补。

[原始问题 - 请参阅下面的更新]

在我开始开发的应用程序中,我有一个包含基类的域命名空间、一个使用这些基类执行操作的服务命名空间,以及一个用于连接数据库的存储库和 DAL 命名空间。

我认为最简单的方法是在服务命名空间中使用继承来添加像 LoadFromDb 这样的过程,但是当我开始实施时,我发现这种方法通常需要最多的代码,因为我必须分配所有类属性两次(一次在存储库命名空间中,然后在服务命名空间中)。

这是一个例子。我可以让选项 2 和选项 3 工作,但我希望在精神上更接近选项 1。

namespace Domain
{
    public class Request
    {
        public int RequestID{get; set;}
        public string RequestingUser {get; set;}
        public string Title {get; set;}
        public string Description{get; set;}
        public string status {get; set;}
    }
}


namespace app
{
    class MyApp
    {
        void Main()
        {
            //option 1
            Domain.Request x = new Service.svcRequest(5);

            //option 2
            Domain.Request y = new Service.svcRequest(5);

            //option 3
            Domain.Request z = new Domain.Request();
            Service.svcRequest2.loadRequest(5, z);
        }
    }
}

namespace Service
{
    public class svcRequest : Domain.Request
    {
        public svcRequest(int RequestID)
        {
            //this is what I want to do.  
            //  It fails because "this" is read-only 
            //  and because "this" can't be implicitly converted to DomainRequest.
            this = (Domain.Request)repos.Loads.LoadRequest(RequestID);

            //option 2, which is what I'm doing instead for now, but when you get 
            //  to 20 or 50 properties, it's a bit much, 
            //  esp. since those properties have already been assigned once 
            //  within the repository namespace.
            Domain.Request MyRequest = repos.Loads.LoadRequest(RequestID);
            this.RequestID = MyRequest.RequestID;
            this.RequestingUser = MyRequest.RequestingUser;
            this.Title = MyRequest.Title;
            this.Description = MyRequest.Description;
            this.status = MyRequest.status;
        }
    }

    public class svcRequest2
    {
        //option 3.  Much less code, but now I'm not really using inheritance, 
        //  so in my application layer I can't just declare my variable 
        //  and use the svcRequest constructor
        public static void loadRequest(int RequestID, Domain.Request MyRefRequest)
        {
            MyRefRequest = (Domain.Request)repos.Loads.LoadRequest(RequestID);
        }
    }
}

namespace repos
{
    public static class Loads
    {
        public static Domain.Request LoadRequest(int RequestID)
        {
            Domain.Request MyRequest = new Domain.Request();
            DataRow MyRow = dal.Loads.LoadRequestRow(RequestID);
            MyRequest.RequestID = RequestID;
            MyRequest.RequestingUser = (string)MyRow["User"];
            MyRequest.Title = (string)MyRow["Title"];
            MyRequest.Description = (string)MyRow["Description"];
            MyRequest.status = (string)MyRow["Status"];
            return MyRequest;
        }
    }
}

namespace dal
{
    public static class Loads
    {
        public static DataRow LoadRequestRow(int RequestID)
        {
            OleDbConnection dbCon = new OleDbConnection("Provider=SQLOLEDB;Data Source=dbServer;Initial Catalog=RequestDB;User ID=Joe;Password=password");
            string Select = "Select * from RequestTable where ID = " + RequestID;
            OleDbDataAdapter dbRequest = new OleDbDataAdapter(Select, dbCon);
            DataSet dsRequest = new DataSet();
            dbRequest.Fill(dsRequest);
            DataRow drRequest = dsRequest.Tables[0].Rows[0];
            return drRequest;
        }
    }
}

[更新] 这是第二次尝试。我将我的 Domain 命名空间重命名为 Model,并将我的 Service 命名空间重命名为 Domain,我认为这更符合 DDD 约定。按照建议,我在 DAL 中使用的存储库命名空间中添加了一个接口。我现在唯一不能开始工作的是选项 1 的 Load 语句,但我想我只需要多研究一下继承即可。

我是不是越来越近了?

using System;
using System.Data;
using System.Data.OleDb;

namespace Model
{
    public class Request
    {
        public int RequestID{get; set;}
        public string RequestingUser {get; set;}
        public string Title {get; set;}
        public string Description{get; set;}
        public string status {get; set;}
    }
}


namespace App
{
    class MyApp
    {
        void Main()
        {
            //option 1
            Model.Request x = new Domain.dmnRequest(5);

            //option 2
            Model.Request y = new Domain.dmnRequest2(5);

            //option 3
            Model.Request z = new Model.Request();
            Domain.dmnRequest3.loadRequest(5, z);
        }
    }
}

namespace Domain
{
    public class dmnRequest : Model.Request, dal.Request
    {
        public dmnRequest(int requestID)
        {
            //this is what I want to do.  I'm not sure why it's failing
            Load(requestID); 
        }
    }

    public class dmnRequest2 : Model.Request
    {
        public dmnRequest2(int requestID) 
        {
            //option 2; it works but is cumbersome after you hit the 20th property
            dal.Request tmpRequest = new dal.Request();
            tmpRequest.Load(requestID);
            this.RequestID = tmpRequest.RequestID;
            this.RequestingUser = tmpRequest.RequestingUser;
            this.Title = tmpRequest.Title;
            this.Description = tmpRequest.Description;
            this.status = tmpRequest.status;
        }
    }

    public class dmnRequest3
    {
        //option 3.  Much less code, but now I'm not really using inheritance, so in my application layer I can't just declare my variable and use the dmnRequest constructor
        public static void loadRequest(int RequestID, Model.Request MyRequest)
        {
            dal.Request dalRequest = (dal.Request)MyRequest;
            dalRequest.Load(RequestID);
            MyRequest = (Model.Request)dalRequest;
        }
    }
}

namespace repos
{
    public interface SaveMe {void Save(int ID); }
    public interface LoadMe {void Load(int ID); }
}

namespace dal
{
    public class Request : Model.Request, repos.LoadMe
    {
        public void Load(int requestID)
        {
            OleDbConnection dbCon = new OleDbConnection("yaddayadda");
            string Select = "Select * from RequestTable where ID = " + requestID.ToString();
            OleDbDataAdapter dbRequest = new OleDbDataAdapter(Select, dbCon);
            DataSet dsRequest = new DataSet();
            dbRequest.Fill(dsRequest);
            DataRow drRequest = dsRequest.Tables[0].Rows[0];
            this.RequestID = requestID;
            this.RequestingUser = (string)drRequest["User"];
            this.Title = (string)drRequest["Title"];
            this.Description = (string)drRequest["Description"];
            this.status = (string)drRequest["Status"];
        }
    }
}

【问题讨论】:

    标签: c# domain-driven-design ddd-repositories


    【解决方案1】:

    你错了。在 DDD 中,事情非常简单。域只知道由持久层 (DAL) 中的实际存储库类实现的存储库接口。存储库与数据库一起保存/加载域对象(在 DDD 中,这些域对象应该是聚合根)。

    这里没有什么是静态的,存储库应该从数据库中获取它需要的所有数据,然后使用它来恢复对象。存储库总是返回域实体,而不是数据行、数据表、实体框架实体等。这是因为存储库的目的是将域与持久性细节解耦。

    简单地说,Domain 只是说:“嘿,存储库给我这个 id 的 BsuinessEntity”。域告诉存储库要获取什么,而不是如何 获取它。该域并不真正知道涉及数据库。它所看到的只是一个抽象(存储库接口),它与域知道的对象一起工作。

    所有这一切的重点是尊重关注点分离。域关心业务概念和用例,而存储库关心从数据库中存储/检索对象。

    【讨论】:

    • 感谢您的回复。你给了我很多思考。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-19
    相关资源
    最近更新 更多