Фильтр Realm и использование ключа в .NET - PullRequest
0 голосов
/ 17 декабря 2018
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 () внутри него.(Я могу использовать Count () только в транзакциях reaml, но в моем случае это неправильно).

Итак ... Как использовать фильтр области между .NET?

Ответы [ 2 ]

0 голосов
/ 18 декабря 2018
  1. Даже если в документации написано, что синтаксис фильтра области одинаков для всех языков - это не так

  2. *Ключевое слово 1009 * не поддерживается в реализации .NET Realm.(до текущей версии - 3.3.0. Возможно, будет поддерживаться в будущем, но не сейчас)

  3. Подстановка значений в предикат Filter в .Net в настоящее время вообще не поддерживается

  4. Альтернатива BETWEEN для .NET:

.

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

ИтакРешение моего вопроса:

.Filter($"MaxRepeatsPerMonth == 0 OR SUBQUERY(HistoryItems, $hi, $hi.DoneTime >= {monthStartStr} && $hi.DoneTime <= {monthEndStr}).@count <= MaxRepeatsPerMonth"); 
0 голосов
/ 17 декабря 2018

Вы можете установить формат даты, например, 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_

Редактировать

Вместо Filter использовать Where

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);
...