2

更新:这是一个更充分地展示了这个问题的要点https://gist.github.com/pauldambra/5051550


啊,更多更新...如果我将 Mailing 类的 Id 属性设为字符串,那么一切正常。我应该放弃整数ID吗?


我有 2 个模型

public class Mailing
{
    public int Id { get; set; }
    public string Sender { get; set; }
    public string Subject { get; set; }
    public DateTime Created { get; set; }
}

public class Recipient
{
    public Recipient()
    {
        Status = RecipientStatus.Pending;
    }
    public RecipientStatus Status { get; set; }
    public int MailingId { get; set; }
}

在我的主页上,我想获取最后 10 封邮件。计算他们的接收者(最终计算不同状态的接收者,但是......)

我做了以下索引

public class MailingWithRecipientCount : AbstractMultiMapIndexCreationTask<MailingWithRecipientCount.Result>
        {
            public class Result
            {
                public int MailingId { get; set; }
                public string MailingSubject { get; set; }
                public string MailingSender { get; set; }
                public int RecipientCount { get; set; }
            }

            public MailingWithRecipientCount()
            {
                AddMap<Mailing>(mailings => from mailing in mailings
                                                 select new
                                                            {
                                                                MailingId = mailing.Id,
                                                                MailingSender = mailing.Sender,
                                                                MailingSubject = mailing.Subject,
                                                                RecipientCount = 0
                                                            });
                AddMap<Recipient>(recipients => from recipient in recipients
                                                    select new
                                                               {
                                                                   recipient.MailingId,
                                                                   MailingSender = (string) null,
                                                                   MailingSubject = (string)null,
                                                                   RecipientCount = 1
                                                               });
                Reduce = results => from result in results
                                    group result by result.MailingId
                                    into g
                                    select new
                                               {
                                                   MailingId = g.Key,
                                                   MailingSender = g.Select(m => m.MailingSender)
                                                                    .FirstOrDefault(m => m != null),
                                                   MailingSubject = g.Select(m => m.MailingSubject)
                                                                     .FirstOrDefault(m => m != null),
                                                   RecipientCount = g.Sum(r => r.RecipientCount)
                                               };
            }
        }

我查询使用

public ActionResult Index()
        {
            return View(RavenSession
                        .Query<RavenIndexes.MailingWithRecipientCount.Result, RavenIndexes.MailingWithRecipientCount>()
                        .OrderByDescending(m => m.MailingId)
                        .Take(10)
                        .ToList());
        }

我得到:

System.FormatException:System.FormatException:输入字符串的格式不正确。在 System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)

任何帮助表示赞赏

4

1 回答 1

4

是的,整数 id 很痛苦。这主要是因为 Raven 总是存储一个完整的字符串文档密钥,并且您必须考虑何时使用该密钥或您自己的 id 并进行适当的翻译。归约时,还需要对齐 int 和 string 数据类型。

让您的测试通过的最低要求是:

// in the "mailings" map
MailingId = mailing.Id.ToString().Split('/')[1],

// in the reduce
MailingId = g.Key.ToString(),

但是-您可以通过将发件人和主题字符串从中取出来使您的索引更小并且性能更好。您可以通过转换将它们放入。

这是一个简化的完整索引,它做同样的事情。

public class MailingWithRecipientCount : AbstractIndexCreationTask<Recipient, MailingWithRecipientCount.Result>
{
    public class Result
    {
        public int MailingId { get; set; }
        public string MailingSubject { get; set; }
        public string MailingSender { get; set; }
        public int RecipientCount { get; set; }
    }

    public MailingWithRecipientCount()
    {
        Map = recipients => from recipient in recipients
                            select new
                            {
                                recipient.MailingId,
                                RecipientCount = 1
                            };

        Reduce = results => from result in results
                            group result by result.MailingId
                            into g
                            select new
                            {
                                MailingId = g.Key,
                                RecipientCount = g.Sum(r => r.RecipientCount)
                            };

        TransformResults = (database, results) =>
                           from result in results
                           let mailing = database.Load<Mailing>("mailings/" + result.MailingId)
                           select new
                           {
                               result.MailingId,
                               MailingSubject = mailing.Subject,
                               MailingSender = mailing.Sender,
                               result.RecipientCount
                           };
    }
}

顺便说一句,您知道RavenDB.Tests.Helpers包吗?它提供了一个简单的基类RavenTestBase,您可以从中继承它,它为您完成了大部分工作。

using (var store = NewDocumentStore())
{
    // now you have an initialized, in-memory, embedded document store.
}

另外 - 您可能不应该在单元测试中扫描程序集的索引。您可能会引入不属于您正在测试的部分的索引。更好的方法是单独创建索引,如下所示:

documentStore.ExecuteIndex(new MailingWithRecipientCount());
于 2013-02-27T22:48:30.750 回答