什么从DAL返回到BLL

时间:2009-04-06 00:11:18

标签: asp.net architecture data-access-layer bll

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

我在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对象并将其返回,但这似乎不对。 还有另一种方法吗?

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

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

谢谢!

7 个答案:

答案 0 :(得分:5)

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

从db填充对象,然后将其发送到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;}
    }

}

DAL书:

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 Book:

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。

答案 1 :(得分:2)

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

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

答案 2 :(得分: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的另一个好处是你可以缓存查找。您可以拥有一个包含您查找过的书籍的词典,以减少对已经返回的对象的额外数据库调用。当发生更新时,你删除了缓存的实体......这是另一篇文章。

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

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

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

祝你好运: - )

答案 3 :(得分:1)

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

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

项目BLL参考DAL和DomainModel

Project DAL参考DomainModel

项目UI参考BLL和DomainModel

Project DomainModel什么都没引用

答案 4 :(得分:0)

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

答案 5 :(得分:0)

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

答案 6 :(得分: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等建议...但是你没有使用预期的模型,并且可能将它全部扔进一个程序集中,因为你不会无论如何能够独立地保持它。

相关问题