【问题标题】:Realm's Filter and BETWEEN keywod usage in .NET.NET 中的领域过滤器和 BETWEEN 关键字使用
【发布时间】:2018-12-17 14:30:26
【问题描述】:
public class Quest : RealmObject
{
    [PrimaryKey]
    public string Id { get; set; } = Guid.NewGuid().ToString();

    public DateTimeOffset StartDate { get; set; }
    public DateTimeOffset EndDate { get; set; }

    public string Name { get; set; }

    public int MaxRepeats { get; set; } 

    [Backlink(nameof(HistoryItem.Quest))]
    public IQueryable<HistoryItem> HistoryItems{ get; }       
}

public class HistoryItem : RealmObject
{
    [PrimaryKey]
    public string Id { get; set; } = Guid.NewGuid().ToString();

    public DateTimeOffset DoneTime { get; set; }

    public Quest Quest { get; set; }
}

我需要得到什么:

  1. 在 1 天的日期范围内过滤
  2. 保留所有 MaxRepeats == 0 的任务 + 过滤其余已完成的任务
  3. 保留 MaxRepeatsPerMonth == 0 的所有任务 + 过滤已完成的其余任务 --问题

我当前的代码是:

private IQueryable<Quest> SearchQuery(DateTime day)
{
    var dayStart = day.AddMilliseconds(-100);
    var dayEnd = day.AddHours(24).AddMilliseconds(100);

    var monthStart = day.Date.AddDays(-day.Day +1).AddMilliseconds(-100);
        int daysInMonth = DateTime.DaysInMonth(day.Year, day.Month);
    var monthEnd = monthStart.AddDays(daysInMonth).AddMilliseconds(200);

    return _db.Realm.All<Quest>().Where(a => a.StartDate < dayStart &&
                                             a.EndDate > dayEnd) // done 1
                              .Filter("MaxRepeats == 0 OR HistoryItems.@count <= MaxRepeats") // done 2
                              .Filter("MaxRepeatsPerMonth == 0 OR (HistoryItems.DoneTime BETWEEN {%@, %@}).@count <= MaxRepeatsPerMonth"); //an Issue
}

我已经找到了 Swift 的解决方案(过滤器语法对所有语言都是一样的)......但是不可能写

_db.Realm.All<HistoryItem>().Filter("DoneTime BETWEEN {%@, %@}", date1, date2);

因为过滤器在.NET中只有一个输入参数

我不能写:

_db.Realm.All<HistoryItem>().Filter("DoneTime BETWEEN {"+ date1+","+ date2 + "}");

在这种情况下,日期将以另一种 DateTime 格式写入,而不是 Filter() 方法所需的格式。

我也不能使用 Where() 方法,因为它有一个限制,我不能在其中使用 Count()。 (我只能在 reaml 事务中使用 Count(),但在我的情况下这样做是错误的)。

那么...如何在 .NET 中使用领域的过滤器?

【问题讨论】:

    标签: c# realm subquery


    【解决方案1】:
    1. 即使在编写的文档中,领域过滤器的语法对于所有语言都是相同的 -- 这不是真的

    2. BETWEEN 关键字在 Realm 的 .NET 实现中不支持。 (直到当前版本 -- 3.3.0。将来可能会支持,但现在不支持)

    3. 目前根本不支持在 .Net 中将值替换为 Filter 谓词

    4. .NET 的 BETWEEN 的替代方案是:

    .

    .Filter($"HistoryItems.DoneTime >= {monthStartStr} && HistoryItems.DoneTime <= {monthEndStr}");
    

    所以我的问题的解决方案是:

    .Filter($"MaxRepeatsPerMonth == 0 OR SUBQUERY(HistoryItems, $hi, $hi.DoneTime >= {monthStartStr} && $hi.DoneTime <= {monthEndStr}).@count <= MaxRepeatsPerMonth"); 
    

    【讨论】:

      【解决方案2】:

      您可以设置日期的格式,例如outputDate.ToString("yyyy-MM-dd")

      https://docs.microsoft.com/en-us/dotnet/api/system.datetimeoffset.tostring?view=netframework-4.7.2#System_DateTimeOffset_ToString_System_String_


      编辑

      Where代替Filter

      https://realm.io/docs/dotnet/latest/#queries

      _db.Realm.All<Quest>().Where(a => a.StartDate < dayStart && a.EndDate > dayEnd)
          .Where(x => x.MaxRepeats == 0 || x.HistoryItems.Count() <= x.MaxRepeats)
          .Where(x => MaxRepeatsPerMonth == 0 ||
                      x.HistoryItems.Count(q => q.DoneTime >= date1 && q.DoneTime <= date2) <= MaxRepeatsPerMonth);
      

      【讨论】:

      • ofc 我可以,但是 1. 这是错误的方式,必须是本地方式将 dateTime obj 粘贴到过滤器中; 2. NSPredicate 内部的 DateTime 看起来像“566752095.510604”,所以这种方式行不通。
      • 不,这个问题与“过滤器”和“之间”的用法有关。就我而言,我将无法使用 Where() 方法解决我的任务。我需要完全过滤,因为由于限制,我将有一个无法在“Where()”中写入的附加条件
      • 可以多次使用Where子句,非常强大。我更新了我的答案
      • 这是不可能的,因为 Count() 不能在那里使用。计数只能在过滤器方法或领域事务内部使用。所以我唯一的方法就是编写过滤器方法。我不能使用 Where() - 它对领域的使用有限制。
      • 我已经解决了任务。但仍然需要你的帮助,朋友
      猜你喜欢
      • 1970-01-01
      • 2013-11-04
      • 1970-01-01
      • 2021-07-26
      • 2023-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多