问题
I have table structures that look like below:
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
I want to use OrmLite to generate SQL similar to below:
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
Because I want to have a strongly typed global filter to filter out result by tenantId (on database side) I have code looks like below
public List<TOut> Exec<TIn, TOut>(SqlExpression<TIn> exp) where TIn : IHaveTenantId
{
exp.Where(x => x.TenantId == _tenantId);
return _conn.Select<TOut>(exp);
}
The poco of Sale looks like below:
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
}
And I'm trying to use strongly typed LeftJoin syntax like below:
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));
I couldn't figure out how to join the same table multiple times and have an alias per join (e.g. left join contact as 'seller', hence I can select seller.FirstName, buyer.FirstName) and I don't want to use parameterised raw sql.
Is this possible at all with OrmLite?
回答1:
Support for typed JOIN aliases were added in v4.0.62, e.g:
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"),
});
Prior to v4.0.62 you can continue to use a Typed SqlExpression
with custom SQL for this, e.g:
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");
The benefit of which is that it still leaves a Typed API where you can add additional filters like a global TenantId filter, e.g:
q.Where(x => x.TenantId == tenantId);
And then project it into your Custom POCO with:
var sales = db.Select<SaleView>(q);
The new CustomJoin
API is available from v4.0.37+ that's now available on MyGet.
来源:https://stackoverflow.com/questions/28019508/how-to-leftjoin-to-the-same-table-twice-using-servicestack-ormlite