2

假设我们有一个用 C# 表示的 SQL 表,如下所示:

public class Product
{
   public int ID { get; set; }
   public string Name { get; set; }
   public string Picture { get; set; } // filename of the picture, e.g. apple.jpg
   public int CategoryID { get; set; }
}

现在我们将查询数据库并检索对象,假设使用如下值:

ID = 1
Name = Yellow apple
Picture = apple.jpg
CategoryID = 25

一切都很正常。我现在正在思考的事情是:如果我想展示一个产品,我需要一些没有从数据库中查询到的附加信息,比如图像的确切文件路径,我们所拥有的只有

苹果.jpg

,但我们可能需要类似的东西

〜/图像/苹果.jpg


所以,我在想3种可能性:

1.) 向 Product 类添加一个新属性

public string PictureUrl
{
    get
    {
        return "~/images/apple.jpg";
    }
}

2.) 在执行表示逻辑期间指定完整的 url,比如说:

public void ShowProductDetails()
{
    Product p = ProductRepo.GetProduct(id);

    txtName.Text = p.Name;
    imgPicture.ImageUrl = "~/images/" + p.Picture;
}

3.) 使用装饰器模式

第一种方法对我来说似乎是错误的(即使我已经使用了很长时间),因为我正在尝试使用分层的 Web 应用程序。我不确定硬编码这是一个好方法。

第二种方法更好,但更糟糕的是它不能轻易重用。如果我有多个地方在做同样的事情并且发生了一些变化,......如果我指定一些保存路径的静态常量,也许它会起作用......

第三种可能性在可维护性方面似乎相当复杂。我的班级数量可能要翻倍。如果我现在有 30 节课,它会突然变成 60 节:/

做这样的事情的最佳/推荐方式是什么?如果我向我的 POCO 添加不包含在 db 架构中的属性,我将无法使用 Dapper.Contrib 或 Rainbow 和类似的库,因为即使“选择”工作正常,我也无法“插入”或“删除”。我必须为每个命令硬编码 sql 字符串,这在一段时间后变得非常乏味,当你一直在做同样的事情时。

编辑:

Govind KamalaPrakash Malviya 的解决方案很棒,但不能每次都使用。我需要一种方法来解决任何类型的属性,即使是那些更复杂的属性 - 例如某些相册的照片数量。将照片的数量与相册一起查询是个好主意,但将其分配给什么?使用装饰器模式创建装饰类?

您如何解决此类架构问题?

4

2 回答 2

4

我认为您应该在表示层中对其进行操作,因为仅表示层的图像路径。所以使用第三个,但使用实用程序方法更容易

public class PathUtility
{
    public static string ImageUrl(string imageName)
    {

          if(string.IsNullOrEmpty(imageName))
          {
               throw new Exception("Image name not valid!!");
          } 
          else
          {
               return "YourImageDirectroyUrl" + imageName;
          }

    } 
}

并轻松使用

PathUtility.ImageUrl("apple.jpg");
于 2012-06-30T15:44:40.480 回答
1

我通常通过保留实体对象并创建一个额外的数据容器来解决这个问题,该容器将保存对相应实体的引用或实现实体对象本身的相应属性。在后一种情况下,我使用映射库 ( AutoMapper ) 将数据从实体复制到增强的容器。

填充额外属性的逻辑通常位于工厂(或工厂方法)中。这取决于你,你想把它放在你的架构中的什么地方。在当前的项目中,我们将它们包含在客户端的数据访问外观中,因为我们不想让太多的 DTO 使数据访问层混乱。这当然意味着,数据访问层仍然需要支持检索额外的属性。在您的情况下,像int GetNumberOfPhotosForAlbum(Album album).

我们发现,数据访问层不断增长的合约带来的好处超过了风险,这当然可能需要支持许多不同的调用,例如上面的示例,而不仅仅是EnhancedAlbum GetEnhancedAlbumWithAllKindsOfExtraProperties(long albumId). 在某些情况下,这也可能成为性能问题,因为服务调用频率增加会产生开销。最后,您需要决定什么最适合您的项目。

我喜欢这种方法,因为我的实体Album

例子:

class Album
{
    string Name { get; set; }
}

class EnhancedAlbum
{
    Album Album { get; set; }
    int NumberOfPhotos { get; set; }
}

class EnhancedAlbumFactory
{
    private MyDataService _dataService;

    //include some means of constructing or (better) injecting the data service

    EnhancedAlbum GetEnhancedAlbum(Album album)
    {
        return new EnhancedAlbum
               {
                   Album = Album,
                   NumberOfPhotos = _dataService.GetNumberOfPhotosForAlbum(album);
               };
    }
}
于 2012-07-01T14:42:04.120 回答