【问题标题】:Realm.io Many-to-ManyRealm.io 多对多
【发布时间】:2021-03-26 20:30:42
【问题描述】:

我在弄清楚如何正确建模我的领域中的多对多关系时遇到一些问题,即围绕领域对象始终处于活动状态这一事实。

所以这里讨论的模型围绕两个对象:事件和库存。一个事件可以有多个分配给它的库存项目(想想椅子、盘子、叉子等),一个库存项目可以分配给多个事件。当我们将它分配给一个事件时,我们定义了我们想要分配给该事件的所述项目的数量。然而,这就是问题出现的地方,因为领域对象始终处于活动状态并且对象类型相同,所以无论事件有什么数据都会影响我的库存数据行。

总体情况是,当我进入库存详细信息视图时,我想显示为每个即将发生的事件分配了多少物品。例如,我可能总共有 50 个椅子,我已经为明天的活动分配了 40 个,这意味着如果有人试图安排当天的活动,我不能再分配 20 个。

我的 Realm 对象如下所示:

public class Event : RealmObject
{
    [PrimaryKey]
    public string EventId { get; set; } 
    [Indexed]
    public string VenueId { get; set; }
    [Indexed]
    public string Name { get; set; }
    public DateTimeOffset DateOfEventUTC { get; set; }
    public IList<Inventory> Items { get; }
}

public class Inventory : RealmObject
    {
        [PrimaryKey]
        public string InventoryId { get; set; }
        [Indexed]
        public string VenueId { get; set; }
        public Category Category { get; set; }
        public int Count { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        [Backlink(nameof(Event.Items))]
        public IQueryable<Event> Events { get; }
    }

然后我尝试在我的虚拟机中做我想做的事情(即显示为该事件分配了多少项目):

var item = unitOfWork.InventoryRepository.GetById(inventoryId);
            var nextMonth = DateTime.UtcNow.AddMonths(1);
            AssignedEvents = item.Events
                .Where(x => x.DateOfEventUTC >= DateTime.UtcNow && x.DateOfEventUTC <= nextMonth)
                .ToList()
                .Select(x => new AssignedEventModel
                {
                    DateOfEventUTC = x.DateOfEventUTC.DateTime,
                    Name = x.Name,
                    AssignedItems = x.Items.First(z => z.InventoryId == inventoryId).Count
                })
                .ToList();

不幸的是,这就是问题所在。我尝试按照领域文档中的建议应用 [Ignored] 标签,以便不再保留该项目。不幸的是,这并没有解决我的问题。我还是新手,我对 SQL 比对 NoSQL 更熟悉

【问题讨论】:

  • 我能够解决这个问题,而不是在我的领域中尝试多对多,我只是查询我的事件表,而不是拥有 IList of Inventory,而是在我模仿库存的领域数据库。因此,Inventory 无法看到它与多个事件相关的事实。看起来很老套,处理这个问题的方法不正确
  • 实际问题不是很清楚。如果您的目标是显示为每个即将到来的事件分配了多少项目,您将在每个事件中使用public IList&lt;Inventory&gt; Items { get; } 的计数。如果您想查看周六的活动是否需要多少椅子,请查询这些活动并获取项目的总和。
  • 所以我可能没有解释得太清楚,但是作为一个整体的问题是如何在 Realm 中正确地建模 M 到 M 关系而不影响实际的子组件。例如:假设我有一个计数为 40 的项目,并且事件说只有 20 个被分配给该项目,因为它们是同一个对象,该事件具有的集合将覆盖领域中的单个项目本身
  • Realm 不是这样工作的。如果您有一个包含 20 把椅子列表的事件,则对椅子本身没有影响,因为它是对每把椅子的指针或引用。椅子不知道该事件并且椅子不是同一个对象;它们是 20 个不同的椅子对象,没有任何内容被覆盖。如果您随后为每把椅子添加反向关系,则它是对椅子所属的 events(复数)的引用。在这种情况下,当您将椅子添加到事件中时,会自动创建一个反向关系并将其添加到椅子上,这样它就会知道它所属的事件。
  • 可以应用一个过滤器,根据列表中与该过滤器匹配的项目数返回计数。假设有 20 把椅子和 12 张桌子的活动。您的IList&lt;Inventory&gt; Items 将包含总共 32 个库存项目,您可以直接过滤这些项目的数量。一般 - 类似于numChairsForThisEvent = someEvent.Items.filter("name == 'chair'").count。这将返回 20 的计数。您可以将该数字与椅子的总数(来自 Inventory 对象)进行比较。此外,您还可以获得即将举行的活动总共需要多少把椅子。

标签: c# xamarin.forms realm


【解决方案1】:

我也很难看出这在 SQL 中是如何工作的,但我不是这方面的专家,所以我可能会错过一些细节,这些细节会让它以你的结构方式工作。 回到我们的案例:问题与 Realm 的实时性关系不大,而更多地与您构建域模型的方式有关。 如果您使用相同的“库存”模型做两件事:

  1. 跟踪每个项目的总金额
  2. 跟踪特定活动中使用的每个库存项目的数量

您会对 Count 真正代表的内容有疑问。 创建第三个模型将解决您的所有问题。

  1. 库存 => 商品总量
  2. Event => 表示事件及其所有数据
  3. EventInventory => 表示该事件中使用的物品数量

没有太多关于您的项目和其他模型的信息(请参阅 AssignedEventModel 等)我可以建议一些类似的东西

class Event : RealmObject
{
    [PrimaryKey]
    public string EventId { get; set; }

    // ... other fields you need ...

    public DateTimeOffset DateOfEventUTC { get; set; }

    [Backlink(nameof(EventInventory.Event))]
    public IList<EventInventory> Items { get; }
}

class EventInventory : RealmObject
{
    public Inventory Inventory { get; set; }

    public int Count { get; set; }

    public Event Event { get; set; }
}

class Inventory : RealmObject
{
    [PrimaryKey]
    public string InventoryId { get; set; }

    // ... other fields you need ...
    
    public int TotalCount { get; set; }

    [Backlink(nameof(EventInventory.Inventory))]
    public IQueryable<EventInventory> EventInventories { get; }
}

然后在你的库存虚拟机中

var inventory = unitOfWork.InventoryRepository.GetById(inventoryId);
var inUse = inventory.EventInventories
    .Where(x => /*...*/)
    .Sum(x => x.Count);

// your databind count that want to show under Inventory's View
remainingCount = inventory.TotalCount - InUseCount;

所以基本上,现在您可以计算某个 InventoryItem 在某个时间范围内的剩余可用量。使用这些模型,您应该能够在需要时创建您的AssignedEventModel。 我希望这会有所帮助。

在一个侧节点上,我注意到您正在使用 unitOfWork 和存储库模式(至少,看起来如此)。尽管它看起来可能是个好主意,但在使用 Realm 时通常不赞成使用它。这仅仅是因为您将错过 Realm 的一些强大功能。 您可以在答案的“存储库”部分阅读有关此here 的更多信息。

【讨论】:

  • 您已经为这个答案付出了很多努力,但尚不清楚解决了什么问题。请参阅我的问题。 OP 唯一需要做的就是将 Inventory 对象的反向关系添加回事件。这样做后,他们可以获得每个事件的总库存、库存与哪些事件以及库存用于多少事件。问题中所述的目的是即显示为该事件分配了多少项目,这很容易通过获取领域列表的计数来完成:Events.item。也许你可以澄清一下?
  • OP 希望每种类型都有一个集中的可用项目数量(x 字符数量等)。同时,他/她想将每种类型中的一些分配给这个和那个事件。这些作业需要记录在某个地方,这就是为什么他/她需要第三个模型来记录。记录后,她/他可以根据在该时间范围内采取多少 x 类型的项目来决定下一个事件是否最多可以有 y 个椅子。这至少是我从这个问题中得到的。
  • 好的,谢谢你的解释。不需要第三个模型。它只是从public int Count { get; set; } 中获取可用椅子的总量并减去所需的总量,这是来自事件public IList&lt;Inventory&gt; Items { get; } 属性的总和,或者如果添加了反比关系,那么您就知道椅子的所有事件上使用。但是,正如您所指出的,第三个对象也是一种选择!
  • 用户对记录每个事件使用的每个项目的数量表现出浓厚的兴趣,所以我为此提供了一个解决方案。但是您所说的实现了相同的目的:跟踪库存中的所有事件并使用时间范围过滤扫描列表。这变得有点复杂,即每次打开库存时评估整个事件列表。如果用户觉得这很容易推理并且性能(可能缓存通知更改)是可以接受的,我想这也可以。
  • 每个事件使用的每个项目的数量直接来自事件中项目列表中项目数量的计数 - 就像这个伪代码 let chairsUsed = event.Items.count .所以它已经存储了;请记住,List 的行为与数组非常相似,并且具有许多功能,添加、删除和...计数!
猜你喜欢
  • 2015-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多