如何使用ServiceStack OrmLite将LeftJoin两次连接到同一个表?

时间:2015-01-19 07:06:23

标签: servicestack left-join ormlite-servicestack

我的表结构如下所示:

table Tenant: Id[PK], etc
table Contact: Id[PK], FirstName, LastName etc
table Sale: Id[PK], TenantId[FK], SellerId[FK], BuyerId[FK], etc

SellerId is a FK to Contact.Id
BuyerId is a FK to Contact.Id
TenantId is a FK to Tenant.Id

我想使用OrmLite生成类似于下面的SQL:

select  sale.*
    ,   buyer.FirstName 'BuyerFirstName'
    ,   buyer.LastName 'BuyerLastName'
    ,   seller.FirstName 'SellerFirstName'
    ,   seller.LastName 'SellerLastName'
from    sale
    left join
        contact seller
    on  sale.SellerId = seller.Id
    left join
        contact buyer
    on  sale.BuyerId = buyer.Id
where   tenantId = 'guid' -- this is being filtered at a global level

因为我希望有一个强类型全局过滤器来过滤掉tenantId的结果(在数据库端)我的代码如下所示

public List<TOut> Exec<TIn, TOut>(SqlExpression<TIn> exp) where TIn : IHaveTenantId
{
    exp.Where(x => x.TenantId == _tenantId);
    return _conn.Select<TOut>(exp);
}

Sale的poco如下所示:

public class Sale : IHaveTenantId
{
    public Guid Id { get; set; }

    [ForeignKey(typeof(Contact), OnDelete = "CASCADE")]
    public Guid BuyerId { get; set; }

    [ForeignKey(typeof(Contact), OnDelete = "CASCADE")]
    public Guid SellerId { get; set; }

    //etc
}

我尝试使用强类型的LeftJoin语法,如下所示:

public class SaleView
{
    public Guid Id { get; set; }
    public string BuyerFirstName { get; set; }
    public string SellerLastName { get; set; }
    //etc
}

var result = Exec<SaleView, Sale>(_conn
    .From<Sale>()
    .LeftJoin<Contact>((sale, seller) => sale.SellerId == seller.Id)
    .LeftJoin<Contact>((sale, buyer) => sale.BuyerId == buyer.Id));

我无法弄清楚如何多次加入同一张桌子,并且每个联接都有一个别名(例如,左边加入联系人作为&#39;卖家&#39;,因此我可以选择卖家。第一名,买家。 FirstName)我不想使用参数化原始sql。

OrmLite可以实现这一点吗?

1 个答案:

答案 0 :(得分:4)

支持typed JOIN aliases were added in v4.0.62,例如:

var q = db.From<Sale>()
    .LeftJoin<ContactIssue>((s,c) => s.SellerId == c.Id, db.JoinAlias("seller"))
    .LeftJoin<ContactIssue>((s,c) => s.BuyerId == c.Id, db.JoinAlias("buyer"))
    .Select<Sale, ContactIssue>((s,c) => new {
        s,
        BuyerFirstName = Sql.JoinAlias(c.FirstName, "buyer"),
        BuyerLastName = Sql.JoinAlias(c.LastName, "buyer"),
        SellerFirstName = Sql.JoinAlias(c.FirstName, "seller"),
        SellerLastName = Sql.JoinAlias(c.LastName, "seller"),
    });

在v4.0.62之前,您可以继续使用带有自定义SQL的Typed SqlExpression,例如:

var q = db.From<Sale>()
    .CustomJoin("LEFT JOIN Contact seller ON (Sale.SellerId = seller.Id)")
    .CustomJoin("LEFT JOIN Contact buyer ON (Sale.BuyerId = buyer.Id)")
    .Select(@"Sale.*
        , buyer.FirstName AS BuyerFirstName
        , buyer.LastName AS BuyerLastName
        , seller.FirstName AS SellerFirstName
        , seller.LastName AS SellerLastName");

其好处是它仍然保留了一个Typed API,您可以在其中添加其他过滤器,例如全局TenantId过滤器,例如:

q.Where(x => x.TenantId == tenantId);

然后将其投影到您的自定义POCO中:

var sales = db.Select<SaleView>(q);

新的CustomJoin API可从 v4.0.37 + 获得now available on MyGet