【问题标题】:RavenDB Ids and ASP.NET MVC3 RoutesRavenDB Id 和 ASP.NET MVC3 路由
【发布时间】:2012-02-07 22:47:58
【问题描述】:

只需使用 MVC 3 RC2 和 RavenDB 构建一个快速、简单的站点来测试一些东西。

我已经做了很多项目,但我很好奇 Html.ActionLink() 如何处理 raven DB ID。

我的示例:我有一个名为“原因”的文档(某事的原因,主要是文本),其中包含原因文本和链接列表。我可以通过我的存储库添加、删除和执行其他所有操作。

下面是我的剃刀视图的一部分,它在项目符号列表中列出了每个原因,第一个文本是编辑链接:

@foreach(var Reason in ViewBag.ReasonsList)
{
    <li>@Html.ActionLink("Edit", "Reasons", "Edit", new { id = Reason.Id }, null) @Reason.ReasonText</li>
    <ul>
    @foreach (var reasonlink in Reason.ReasonLinks)
    { 
        <li><a href="@reasonlink.URL">@reasonlink.URL</a></li>
    }
    </ul>
}

问题

这工作正常,除了编辑链接。虽然此处的值和代码似乎可以直接工作(即链接直接触发),但 RavenDB 将我的文档 ID 保存为“reasons/1”。

因此,当 URL 发生并传递 ID 时,生成的路由是“http://localhost:4976/Reasons/Edit/reasons/2”。因此,ID 已正确附加,但 MVC 将其解释为自己的路由。

关于如何解决这个问题的任何建议?我需要创建一个特殊的路线来处理它还是我可以做些什么?

【问题讨论】:

  • 完美!我遵循了第二个解决方案(将星号放在 Routes 中的 Id 前面),但这篇文章正是我想要的。)我将添加第二个答案来解释我究竟做了什么,但这是绝对是正确的答案。谢谢!
  • @goober _ 我的书签中有那个链接已经很久了。很高兴它终于得到了很好的利用。

标签: asp.net-mvc asp.net-mvc-3 actionlink ravendb


【解决方案1】:

我刚刚下载了最新版本的 RavenDB 并试用了一下。

public class Entity {
    public int Id { get;set; }
    public string Text { get;set; }
}

当我将它保存到 RavenDB 时,Raven 中的 id 是“entities/1”,但 RavenDB 客户端中的映射能够成功地将 Id 从数据库中的内容解释为我想要的整数。

var entity = session.Load<Entity>(1);
Assert.IsTrue(entity.Id == 1);

你不需要扩展方法,这样你就不需要像上面提到的那样改变任何路由,因为你将处理好的 ol' 整数。字符串 Ids 几乎是一个交易破坏者,但令人惊讶的是,这很有效,所以 RavenDB 又回来了。

  • 注意:我通过观看 Rob Ashton 的演讲并意识到他所有的文档类都有整数作为 Id 发现了这一点。

【讨论】:

  • +1 @Khalid 正是这个。环顾 Ayende 的 Racoon 博客 github.com/ayende/RaccoonBlog,我注意到他经常在本地字符串 Id 和整数 Id 之间进行转换。主要用于放置路线,但好的 ole int 也有其他用途。
  • 它不适用于包含,除非您可以将整数转换为等效的 RavenDb 字符串。
  • 警告!这种在实体类中使用整数 id 的方法在开始使用索引和 map reduce 等时会产生很多痛苦的副作用。这是一个陷阱,我强烈建议使用字符串 Id:s 并在需要演示时转换为整数(url 等) . This post 是非常真实的恕我直言,在我自己经历过一些整数 id 的扭动之后。
【解决方案2】:

在找到@jfar 引用的 Shiju Varghese 博客文章的链接之前,我遇到了类似的问题并想出了自己的解决方案。

它可能不像博文中提供的解决方案那样干净简单,但我相信它仍然可以作为解决方案竞争。所以这里是:

在标准模型类中,当使用 RavenDB 时,我们通常有这样的 id 属性:

public string Id { get; set; }

我所做的是添加另一个 id 属性,如下所示:

public int? IdInt
{
    get { return int.Parse(Id.Substring(Id.IndexOf("/") + 1)); }
}

这将为我们提供给定 RavenDB id 的数字部分。 然后我有一个看起来像这样的类:

[Bind(Exclude = "IdInt")]
public class Item
{
    public string Id { get; set; }
    public int? IdInt
    {
        get { return int.Parse(Id.Substring(Id.IndexOf("/") + 1)); }
    }

    ...
}

请注意,我已排除 IdInt 属性,因为我不希望模型绑定器处理它。 此外,请注意,IdInt 属性可以为空。这是为了避免稍后在创建新项目并且 Id 属性为空时模型绑定器出现问题。

然后在路由中我声明了一个类似这样的规则:

routes.MapRoute(
    "WithParam", // Route name
    "{controller}/{action}/{id}" // URL with parameters
);

稍后使用 ActionLink 或类似的东西,我们可以执行以下操作:

@Html.ActionLink("Details", "Details", new { id = item.IdInt })

最后,当我们按下呈现的链接时,我们会被发送到适当的操作,看起来像这样:

public ActionResult Details(int id)
{
    var item = _session.Load<Item>(id);            
    return View(item);
}

之所以会这样,是因为 Load 方法,它以 ValueType 作为参数,然后自动将数字解析为正确的 RavenDB id。

我们用这种方法实现的是一个看起来像这样的 url:

/items/details/1

正如我在开头所说的,这个解决方案不如之前建议的解决方案那么优雅,但是,这种方法会给你一个更简洁的 url,因为你可以像往常一样使用 id。

【讨论】:

  • 扩展方法不是更好吗? GetMvcSafeId()
【解决方案3】:

仅供参考,@jfar 发布的链接正是这篇文章。以下是我在文章中使用的解决方案:

解决方案 2 - 修改 ASP.NET MVC 路由

修改 ASP.NET MVC 中的路由 Global.asax.cs 文件,如图 以下代码:

 routes.MapRoute(
     "WithParam",                                           // Route name
     "{controller}/{action}/{*id}"                         // URL with parameters
     );  

我们只是在 id 前面加上“*” 将与 RavenDB 的默认 Id 分隔符

【讨论】:

猜你喜欢
  • 2012-04-08
  • 2011-11-24
  • 2012-05-31
  • 2012-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多