10

我目前有一个应用程序,其中包括:用户界面(网页)BLL(管理器和域对象)DAL(我的每个域对象的数据访问类)。

我在 UI 中使用以下内容来搜索域对象。

protect sub Button1_Click()
{
    IBook book = BookManager.GetBook(txtID.Text);
}

这是我的 BLL

public class BookManager 
{
    public static IBook GetBook(string bookId)
    {
        return BookDB.GetBook(bookId);
    }
}

public class Book : IBook
{
    private int? _id
    private string _name;
    private string _genre;

    public string Name
    {
        get { return _name; }
        private set 
        {
            if (string.IsNullOrEmpty(value))
                throw new Exception("Invalid Name");
            _name = value;
        }
    }

    public string Genre
    {
        get { return _serial; }
        private set 
        {
            if (string.IsNullOrEmpty(value))
                throw new Exception("Invalid Genre");
            _genre = value;
        }
    }

    // Other IBook Implementations

}

最后这是我的 DAL

public class BookDB
{
    public static IBook GetBook(int id)
    {
        // Get Book from database using sproc (not allowed to use any ORM)
        // ?? Create IBook Item?
        // return IBook
    }

如何创建一个 IBook 对象并将其返回给 Manager?我正在考虑将一个 DataTable 从 BookDB 返回到 BookManager 并让它创建 Book Object 并返回它,但这似乎不正确。还有另一种方法可以做到这一点吗?

编辑:我决定将每一层分离到一个项目中,并在尝试添加对 BLL 的引用时在 DAL 层中遇到了循环依赖问题。我无法从 DAL 访问 Book Class 或 Interface 或 BLL 中的任何内容。我应该在这里使用 ado.net 对象并让我的经理从 ado.net 对象创建实际对象吗?这是它的布局方式

BLL.Managers - BookManager
BLL.Interfaces IBook
BLL.Domain - Book
DAL - BookDB.

谢谢!

4

7 回答 7

5

您可以创建仅包含数据的虚拟 Book 对象。获取、设置属性和成员值。这本书对数据库中的每个字段都有 1 个属性,但不验证任何内容。

您从数据库中填充对象,然后将其发送到 BLL。

当你想保存对象时,你也将它发送到 BLL。

如果有意义的话,您在 BLL 中的类可以包装这些对象。这样,很容易将其发送回 DAL。

假书:

public class DummyBook:IBook 
{
    private nullable<int> _id;
    private string _name;
    private string _genre;

    public string Id
    {
        get {return _id;}
        set {_id = value;}
    }

    public string Name 
    {
        get {return _name;}
        set {_name = value;}
    }

    public string Genre 
    {
        get {return _genre;}
        set {_genre= value;}
    }

}

达尔书:

public class DALBook 
{
    public static IBook:GetBook(int id) 
    {
        DataTable dt;
        DummyBook db = new DummyBook();

        // Code to get datatable from database
        // ...
        // 

        db.Id = (int)dt.Rows[0]["id"];
        db.Name = (string)dt.Rows[0]["name"];
        db.Genre = (string)dt.Rows[0]["genre"];

        return db;
    }

    public static void SaveBook(IBook book) 
    {
        // Code to save the book in the database
        // you can use the properties from the dummy book
        // to send parameters to your stored proc.
    }
}

BLL 书:

public class Book : IBook
{
     private DummyBook _book;

     public Book(int id) 
     {
         _book = DALBook.GetBook(id);
     }

     public string Name 
     {
         get {return _book.Name;}
         set 
         {
            if (string.IsNullOrEmpty(value))
            {
                throw new Exception("Invalid Name");
            }
            _book.Name = value;
         }
     }

     // Code for other Properties ...



     public void Save()
     {
         // Add validation if required
         DALBook.Save(_book);
     }

}

Edit1:虚拟类应该放在他们自己的项目中(模型,正如评论中所说的那样很好)。参考将按如下方式工作:

DAL 引用模型项目。
BLL 引用模型和 DAL。
UI 引用 BLL。

于 2009-04-06T01:11:16.883 回答
2

BookDB 应该返回 IBook 实例。我喜欢存储库模式,它是关于从数据库到域的映射。

存储库实现返回域对象的实例。这将其余代码与特定的持久性实现屏蔽开来,这可能会受到技术(数据库类型、Web 服务、[插入其他内容])和用于保存数据的格式的影响。

于 2009-04-06T05:25:53.043 回答
1

在我看来,你永远不应该让 DAL 访问 BLL。这是一种不必要的依赖。

将 Book 类放入一个新项目(可能命名为 DomainModel)将修复循环引用。你可以这样做:

BLL 项目参考 DAL 和 DomainModel

项目 DAL 参考 DomainModel

项目 UI 参考 BLL 和 DomainModel

项目 DomainModel 没有参考

于 2009-07-08T04:50:45.183 回答
1

我可能会使用 ExecuteReader 从数据库的代码中创建一个对象。这样做的原因是数据表比读取器具有更多开销,因为它具有更多功能(并且可能是由读取器创建的)。由于您没有使用数据表进行更新/删除,因此您不需要开销。

话虽如此,我会在 BookManager 类中创建一个静态辅助方法。

internal static IBook BookFromReader(IDataReader reader)
{
     Book B = new Book();
     B.Prop = reader.GetString(0);
     B.Rinse = reader.Repeat();
     return B;
}

这样做的原因是因为您拥有接口的原因是因为您可能想要更改实现。您可能最终拥有 INovel : IBook、IReference : IBook 等,然后您会希望在数据层中有一个抽象工厂实现。

public static IBook GetBook(int id)
{
    // SqlCommand Command = new Command("SQL or sproc", ValidConnection);

    using(IDataReader DR = Command.ExecuteReader(id))
    {
        // checking omitted
        switch(DR.GetInt32(1))
        {
            case 0:
                 return BookManager.BookFromReader(DR);
            case 1:
                 return BookManager.NovelFromReader(DR);
            etc
        }
    }
}

这里 DAL 的另一个好处是您可以缓存查找。您可以拥有一个包含您查找过的书籍的字典,以减少对您已经返回的对象的额外数据库调用。发生更新时,您会删除缓存的实体……不过那是另一篇文章。

如果您使用多个程序集,则接口和辅助方法将需要驻留在中性(非依赖)程序集中。现在在 blog-o-sphere 中,正在朝着更少的程序集发展,这意味着更少的依赖等。

这是我阅读的有关此主题的博客的链接:http: //codebetter.com/blogs/patricksmacchia/archive/2008/12/08/advices-on-partitioning-code-through-net-assemblies.aspx

最终,我认为答案是数据层将您的接口实例返回给业务层。

祝你好运 :-)

于 2009-04-06T01:19:53.150 回答
0

您要返回的 DataTable 与数据库相关,对于 BLL,它不应该关心您使用的是什么数据库以及架构是什么。您可以使用 DB-Object Mapper 将 dbtable 映射到 DAL 中的对象。

于 2009-04-06T00:34:06.380 回答
0

如果您不想返回 DataTable,则可以从 BookManager 传入 IBook 实现以填充 DAL。

于 2009-04-06T00:43:55.280 回答
0

遵循预期的模型。数据访问层 (DAL) 负责从数据源检索数据和向数据源发送数据。

DAL 必须不关心您的 BLL 正在使用的任何业务实体,因为它的唯一工作是检索数据并将其返回到中性对象中。对于通用的可重用性,它必须是中性的,否则你最好不要将层分开,因为你正在破坏它的目的。

您的业​​务逻辑层 (BLL) 必须不关心 DAL 如何实现检索或写入数据。

要在 BLL 和 DAL 之间进行通信,您必须使用中性对象。

您的 BLL 将对象的属性作为单独的参数传递给 DAL 中的方法。DAL 中的参数是中性的,使用字符串、int、bool 和任何其他 .NET 对象,这些对象既不是特定于您正在与之通信的数据库版本,也不是特定类型仅存在于您的 BLL 中。

DAL 将通过任何方式从任何地方检索数据,并将中性数据对象返回给调用者。例如,这可能是 DataSet 或 DataTable 或任何其他不特定于您正在使用的数据库类型/版本的对象。因此 DataSet 和 DataTable 是 System.Data 命名空间中的对象,而不是 System.Data.SQL 等...命名空间中的对象。

本质上: - BLL 将中性类型传递给 DAL(例如:string、int、bool、long、float 等) - 如果需要,DAL 负责将这些类型转换为数据库特定类型,然后再将它们传递给数据源DAL 将中性数据类型返回给 BLL(例如:DataSet、DataTable 等) - BLL 负责使用这些中性数据类型的内容来创建、填充和返回特定的业务实体

您的 BLL 必须参考您的 DAL。而已。

当然,您可以完全忽略此模型并破解之前使用 IBOOK 等建议的许多...无论如何都要独立维护它。

于 2010-06-04T11:20:18.717 回答