使用ServiceStack.OrmLite的左连接返回空对象而不是null

6
我是一个有用的助手,可以为您翻译文本。
我已经创建了一个包含我正在尝试做的完整示例的存储库
我的架构如下:
class Order
{
    public int OrderId { get; set; }
}

class LineItem
{
    public int LineItemId { get; set; }
    public int OrderId { get; set; }
}

我正在使用ServiceStack.OrmLite进行订单与LineItem的左连接,使用以下代码:

var query = db.From<Order>()
              .LeftJoin<LineItem>()
              .Where(o => o.OrderId == 1);

var results = db.SelectMulti<Order, LineItem>(query);

SelectMulti() 返回一个 List<Tuple<Order, LineItem>>。当订单没有行项目时,我得到的是 new LineItem() 而不是 null

我希望得到 null,这样我就可以区分“此订单不存在行项目”和“此订单有一个具有默认值的行项目”。

我可以检查行项目的 OrderId 是否等于订单的 OrderId,但理论上我可能有一个 OrderId 为0的订单,那么在这种情况下我将无法区分。

在 OrmLite 中有更好的方法来进行此左连接吗?

2个回答

0
我原本期望得到null,这样我就可以区分“此订单不存在任何行项目”和“此订单有一个带有默认值的行项目”。
使用LEFT JOIN的问题在于该行确实存在,但所有字段都返回为null,OrmLite将其映射到未初始化任何字段的实例中,这与不存在该行的行是无法区分的。
我可以检查行项目的OrderId是否等于订单的OrderId,但理论上我可能会有一个OrderId为0的订单,在这种情况下我将无法判断。
这不应该发生,因为自动递增主键从1(默认值)开始递增。如果您具有int主键并且值为0,则应将其视为无效状态(这很可能表明它已添加不正确),因此检查default(int)即可。

关于PK,有一些情况是PK不需要自增长的,或者DBA选择从0开始而不是1。OrmLite选择不支持这些情况是合理的,因为它们并不常见,但这些情况确实存在。 - Stephen Jennings
如果模型具有非空字段,但数据库在该列中返回null,特别是如果它是主键,那么这表明右侧连接没有行,这是一个相当好的指示。我意识到OrmLite不会询问数据库以确定列是否可为空,但.NET属性为非空可能是一个很好的启发式方法。(另外,我已经查看了OrmLite的实现,我看到为什么这将很难在不进行大量重构的情况下实现。) - Stephen Jennings
@StephenJennings 如果所有字段都为空,且结果集包含PrimaryKey,则我们可以假设null而不是空对象。从技术上讲是可能的,但我想象不出一个场景,在这种情况下订单具有0 PK是“有效”的。 - mythz
一个人造的例子:如果表格是“UnixUsers”而不是“Orders”,那么root可能会有一个PK为0。 - Stephen Jennings
@StephenJennings,UnixUsers表不会有自增的Id。 - mythz

0

我使用的快速而不太优美的解决方案是检查返回的相关对象是否为“empty”。

我用以下小型内联函数实现了这一点:

bool IsEmptyObject<T>(T instance)
{
    var empty = Activator.CreateInstance(instance.GetType());
    return empty.ToJson() == instance.ToJson();
}

这样做效率相当低下,Activator.CreateInstance() 没有被缓存时速度很慢,而且每次都会分配一个新实例。instance.GetType().GetDefaultValue().ToJson() == instance.ToJson() 更加高效,但如果您的类型是结构体或重写了 Equals(),那么使用 instance.GetType().GetDefaultValue().Equals(instance) 会更加高效。 - mythz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接