n层架构:存储业务对象的最佳位置?

时间:2009-12-08 23:42:41

标签: c# .net asp.net 3-tier n-tier-architecture

假设我有一个3层架构(UI,业务和数据)。通常,我创建一个名为“Model”或“Common”的第4个项目来保存我的数据访问对象,然后每个其他项目都会使用这个项目。

现在我正在开发一个项目,其中我的一些数据访问对象具有需要访问Data项目的Save()等方法。所以,如果我试图在Data项目中使用Model / Common项目,我会有一个循环引用。

在这种情况下,保留数据访问对象的最佳位置在哪里?我可以将它保存在Data项目中,但是我的UI项目需要知道数据访问对象,需要访问Data层,这是不好的。

7 个答案:

答案 0 :(得分:8)

我不认为你的n层非常正确。听起来你正在构建更多的2层系统。

在真正的3层项目中,只允许您的数据层与数据库通信。您可以使用“模型”或“常见”项目。那些项目是您的数据层。但是,除非是,应该允许业务层与他们交谈。不应允许您的演示代码与数据层项目进行通信。

当你有超过3个“层”时,n-Tier会进来,但是相同的原理应用程序:每个层只知道如何使用(并且只需要引用)它下面的那个,然后提供api for它上面的层。在我自己的项目中,我采用典型的演示文稿,业务和数据层,并在业务和数据之间提供第4个“翻译”层。这样,数据层可以返回通用类型,如数据集,数据表和数据行,而业务层必须按强类型业务对象工作。转换层在通用数据对象和强类型对象之间进行转换。这样,对传统层之一的更改就不太可能需要对另一层进行更改。

答案 1 :(得分:2)

这就是我项目中的内容。

1。) Application.Infrastructure

  • 所有业务对象,业务对象集合,数据访问类和我的自定义属性和实用程序的基类,作为扩展方法,通用验证框架。这决定了我最终的.net应用程序的整体行为组织。

2。) Application.DataModel

  • 数据库的类型化数据集。
  • TableAdapters扩展到包含我可能需要的交易和其他功能。

3。) Application.DataAccess

  • 数据访问类。
  • 使用基础类型化数据集查询数据库操作的实际位置。

4。) Application.DomainObjects

  • 业务对象和业务对象集合。
  • 枚举。

5.。 Application.BusinessLayer

  • 提供可从Presentation层访问的经理类。
  • HttpHandlers的。
  • 我自己的页面基类。
  • 更多的事情在这里..

6。) Application.WebClient Application.WindowsClient

  • 我的演示文稿图层
  • 从Application.BusinessLayer和Application.BusinessObjects。
  • 获取引用

Application.BusinessObjects在整个应用程序中使用,并且每当需要时它们都会遍历所有层[Application.DataModel和Application.Infrastructure]

我的所有查询都只定义了Application.DataModel。

Application.DataAccess返回或接受Business对象作为任何数据访问操作的一部分。业务对象是在反射属性的帮助下创建的。每个业务对象都标记有一个属性映射到数据库中的目标表,业务对象中的属性使用映射到相应数据库表中的目标列的属性进行标记。

我的验证框架允许我在指定的ValidationAttribute的帮助下验证每个字段。

我的framrwork大量使用Attributes来自动化大多数繁琐的任务,如映射和验证。我还可以将新功能作为框架中的新方面。

示例业务对象在我的应用程序中看起来像这样。

<强> User.cs

[TableMapping("Users")]
public class User : EntityBase
{
    #region Constructor(s)
    public AppUser()
    {
        BookCollection = new BookCollection();
    }
    #endregion

    #region Properties

    #region Default Properties - Direct Field Mapping using DataFieldMappingAttribute

    private System.Int32 _UserId;

    private System.String _FirstName;
    private System.String _LastName;
    private System.String _UserName;
    private System.Boolean _IsActive;

    [DataFieldMapping("UserID")]
    [DataObjectFieldAttribute(true, true, false)]
    [NotNullOrEmpty(Message = "UserID From Users Table Is Required.")]
    public override int Id
    {
        get
        {
            return _UserId;
        }
        set
        {
            _UserId = value;
        }
    }

    [DataFieldMapping("UserName")]
    [Searchable]
    [NotNullOrEmpty(Message = "Username Is Required.")]
    public string UserName
    {
        get
        {
            return _UserName;
        }
        set
        {
            _UserName = value;
        }
    }

    [DataFieldMapping("FirstName")]
    [Searchable]
    public string FirstName
    {
        get
        {
            return _FirstName;
        }
        set
        {
            _FirstName = value;
        }
    }

    [DataFieldMapping("LastName")]
    [Searchable]
    public string LastName
    {
        get
        {
            return _LastName;
        }
        set
        {
            _LastName = value;
        }
    }

    [DataFieldMapping("IsActive")]
    public bool IsActive
    {
        get
        {
            return _IsActive;
        }
        set
        {
            _IsActive = value;
        }
    }

    #region One-To-Many Mappings
    public BookCollection Books { get; set; }

    #endregion

    #region Derived Properties
    public string FullName { get { return this.FirstName + " " + this.LastName; } }

    #endregion

    #endregion

    public override bool Validate()
    {
        bool baseValid = base.Validate();
        bool localValid = Books.Validate();
        return baseValid && localValid;
    }
}

<强> BookCollection.cs

/// <summary>
/// The BookCollection class is designed to work with lists of instances of Book.
/// </summary>
public class BookCollection : EntityCollectionBase<Book>
{
    /// <summary>
    /// Initializes a new instance of the BookCollection class.
    /// </summary>
    public BookCollection()
    {
    }

    /// <summary>
    /// Initializes a new instance of the BookCollection class.
    /// </summary>
    public BookCollection (IList<Book> initialList)
        : base(initialList)
    {
    }
}

答案 2 :(得分:1)

如果您使用的是关系后端,则数据层应按行和列存储信息(如果您愿意,可以使用类型化的DataSet)。没有“业务对象”。

业务层应使用您的“业务对象”。它可以引用BusinessObjects项目。

总结:

  • UI引用了Business和BusinessObjects
  • Business引用了BusinessObjects和Data

希望这有帮助。

答案 3 :(得分:1)

我有一个BusinessObjects项目,服务器端存储映射(ORM)和相应的DataAccess服务,在它们上面公开CRUD操作(还有其他像GetAll)等。

答案 4 :(得分:0)

我建议在模型项目中创建和界面,并在数据层中实现该定义。这样,所有三个(四个?)项目都可以使用该定义,而不知道它是如何实现的。

答案 5 :(得分:0)

在我看来,只有业务层应该具备数据访问对象的知识。它应该在应用自己的业务规则和逻辑时将它们用于数据操作,然后将哑对象(例如数据传输对象)返回到上面的UI层。

您可以使用AutoMapper之类的东西在您的数据和业务对象之间自动映射。

答案 6 :(得分:0)

它真的取决于模式,如果你使用MVC(前端控制器模式),模型是应用程序运行的数据的域特定表示(通常是ORM帮助)我们使用DATA项目这个班。

模型不是数据访问对象,因此数据访问在不同项目中以存储库的形式存在。业务规则服务,最后是Web项目。在这种方法中,所有项目都引用了Data.dll。 模型就像无所不在。

DATA(Domain Model) -> REPOSITORY(Data Access) -> SERVICE(Business Rules) -> WEB