我使用的是ASP.NET MVC 3,将Raven DB用作支持数据存储。我有一组模型,我有兴趣将其转变为ViewModels。为此,我正在利用自动应用程序来照顾将每个属性映射到ViewModel中相应的属性的肮脏工作。假设我有一个类似模型:

public class FooModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int AlphaId { get; set; }
    public int BetaId { get; set; }
}

然后,假设我想将其转换为像这样的视图模型:

public class FooViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int AlphaId { get; set; }
    public Alpha Alpha { get; set; }
    public int BetaId { get; set; }
    public Beta Beta { get; set; }
}

然后,我的地图在应用启动时像这样设置:

Mapper.CreateMap<Foo, FooViewModel>();

然后,在控制器中,我正在执行地图:

public ActionResult FooDetails(string id)
{
    using(var session = this.documentStore.OpenSession())
    {
        var fooInstance = session.Load<Foo>(id);
        var fooViewModel = Mapper.Map<FooViewModel>(fooInstance);
        return this.View(fooViewModel);
    }
}

问题在于,正如您可以看到的,从存储库中传来的实体具有2个属性,这些属性是其他对象的键,类型为alpha和beta。我对基于Alphaid和Betaid Keys的Alpha和Beta的补充感兴趣。

起初,我认为我会利用自动应用程序的自定义转换功能,但是我认为这不会起作用,因为我们需要将数据会话注入映射(致电数据存储以检索Alpha或Beta对象) 。

另一个选择是仅在控制器操作中完成所有工作,但是很快就变得笨拙(在给出的特定示例中不是,但这只是一个说明这一点的示例)。

Alpha和Beta的水合应该在哪里进行,这里的模式是什么?

有帮助吗?

解决方案

也许不是理想的,但是您不仅可以为这两个参考创建地图,还可以在事实之后绘制它们。您仍然必须单独打电话给它们,但是您让汽车应用程序进行重大映射,而不是用自己的地图填充控制器。

public ActionResult FooDetails(string id)
{
    using(var session = this.documentStore.OpenSession())
    {
        var foo = session.Load<Foo>(id).Include(....);
        var alpha = session.Load<Alpha>(foo.AlphaId);
        var beta = session.Load<Beta>(foo.BetaId);

        // null checks

        var fooViewModel = Mapper.Map<FooViewModel>(foo);
        fooViewModel.Alpha = Mapper.Map<AlphaViewModel>(alpha);
        fooViewModel.Beta = Mapper.Map<BetaViewModel>(beta);

        return View(fooViewModel);
    }
}  

我还没有那么多地使用Automapper,但是也许您可以通过MAP功能传递子对象(以在CreationEmap上为Formember链供电)?也许Alexandre的后图建议可能会起作用,但是我看不到您如何在控制器操作中创建地图的“引用”儿童(但是您最好还是直接使用Formember和Raven会话,只有一个mapper.map)。

添加 - 自动应用程序文档提出了类似的嵌套/子图的方法 - https://github.com/automapper/automapper/wiki/nested-mappings. 。尽管它更类似于对象引用,而不是对象ID参考情况。

我还不能对其他答案发表评论,但是关于Pavel的答案 - 您并没有以这种方式使用Raven,没有O/R映射(除了内部JSON->对象)或数据访问层,您只需直接使用Raven会话(也许是通过服务,但肯定不需要存储库或类似内容)。关于引用,字节有正确的问题,正如他对另一个答案之一评论时,最好的方法是存储ID参考并使用Raven Inccivent-它是相同的结果 - 仍然只使用一个请求。

其他提示

我同意那里的人的观点,但是如果您不能扩展模型,您总是可以使用如下图定义映射:

Mapper.CreateMap<Foo, FooViewModel>()
.AfterMap(MapAlphaBetaFromFooToFooViewModel);


public void MapAlphaBetaFromFooToFooViewModel(Foo foo, FooViewModel fooViewModel)
{
// Here the code for loading and mapping you objects
}

这样,当您进行映射时,自动应用程序将在完成基本映射后自动运行该方法。

您可以做的一种优化是从RavendB一次加载相关文档,而不是单独调用以加载每个相关文档。请参阅Ravendb文档 这里.

我想不出任何其他方法来映射那些实体,而不是像您所显示的那样在控制器本身中进行。

您应该首先关心自己的建筑。从数据库加载数据是数据访问层的责任,它不应该知道您的UI是如何组织的。

我认为,最好的方法是以下责任分配:

  1. 数据访问层具有基于POCO的模型,其中实体具有相互参考而不是标识符。该模型暴露于较高的层(例如ViewModel)。
  2. DAL具有单个方法,该方法加载了预期操作所需的所有数据。在您的情况下,它应该加载foo,alpha,beta实体。由于这种情况以DAL方法发生,因此它可能可以在单个DB查询中进行。尽管主要技巧是其他层不在乎它的工作原理。
  3. 然后,在您的控制器中,您使用自动应用程序将Foomodel对象弄平为FooviewModel,这是AutoMapper功能之一。

要点是:

  1. 只有DAL知道它如何加载数据。如有必要,您可以按照自己的意愿进行修改,而无需修改与自动应用程序相关的代码。
  2. 汽车应用程序仅将数据从一个结构映射到另一个结构,并且不会影响数据加载策略。

也就是说,我只会修改您的foomodel:

public class FooModel
{
  public int Id { get; set; }
  public string Name { get; set; }
  public Alpha Alpha { get; set; }
  public Beta Beta { get; set; }
}

以及从DB加载它的代码。

但是,您可能需要原始的类似Foomodel的结构来例如将对象相关的映射定义为简单的结构。但是它仍然完全取决于DAL。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top