I need to rewrite the query below using Linq to Entity. Does someone know how to do it the most sufficient way?
SELECT DISTINCT
C.ClientId,
C.CompanyName
FROM Application A WITH (NOLOCK)
INNER JOIN
(
SELECT ApplicationId
FROM CAContracts WITH (NOLOCK)
WHERE ID = 1212 AND CAContractStatusId IN (2,3)
UNION ALL
SELECT OBA.ApplicationId
FROM OpportunityAssignment OA WITH (NOLOCK)
INNER JOIN OpportunityByApp OBA WITH (NOLOCK) ON
OBA.OpportunityId = OA.OpportunityId
WHERE OA.ID = 1212
AND OA.OpporStatusId IN (5,7)
) ACPA ON
ACPA.ApplicationId = A.Applicationid
INNER JOIN Client C WITH (NOLOCK) ON
C.ClientId = A.ClientId
ORDER BY C.CompanyName
Assuming that Context has all the relevant tables defined already as entities and has proper relationships defined:
Context.Clients
.Include("Applications")
.Include("Applications.CAContracts")
.Include("Applications.OpportunityAssignments")
.Include("Applications.OpportunityAssignments.OpportunityByApps")
.Where<Client>(c => (c.Applications
.Any<Application>(a => a.CAContracts
.Any<CAContract>(cac => cac.ID == 1212 && (cac.CAContractStatusId == 2 || cac.CAContractStatusId == 3)))
|| (c.Applications
.Any<Application>(a => a.OpportunityAssignments
.Any<OpportunityAssignment>(oa => oa.ID == 1212 && (oa.OpporStatusId == 5 || oa.OpporStatusId == 7) && oa.OpportunityByApps.Any<OpportunityByApp>()))))
.Select(c => new { ClientId = c.ClientId, CompanyName = c.CompanyName})
.Distinct()
.OrderBy(c => c.CompanyName);
If I knew more about the schema, I might be able to do a little better. You end up with a collection of anonymous types with ClientId and CompanyName properties; I tend to avoid anonymous types personally unless the corresponding object would otherwise be excessively large.
Related
Hi I have this sql and have to translate into NHibernate QueryOver
SELECT S.Number, S.Description, S.BrandDescription, subquery.vendornumber, subquery.vendorname
FROM Stocks.Stock S left join
(select vendorNumber, VendorName, POLID, LastTransactionDate from
(
SELECT top 4 v.Number vendorNumber, v.Name VendorName, PLL.Id POLID, max(por.TransactionDate) as LastTransactionDate,
ROW_NUMBER() OVER(PARTITION BY v.Number ORDER BY max(por.TransactionDate) DESC) AS rk
FROM Purchasing.PurchaseOrderLineItem PLL
inner join Purchasing.PurchaseOrder po on PLL.PurchaseOrderId = po.Id
inner join Purchasing.PurchaseOrderVendor POV on po.Id = POV.PurchaseOrderId
inner join Purchasing.Vendor V on pov.VendorId = v.Id
left outer join Purchasing.PurchaseOrderReceipt POR on PLL.Id = por.PurchaseOrderLineItemId
group by v.Number, v.Name,PLL.Id
order by LastTransactionDate desc
) subquery
where subquery.rk = 1) B on PL.Id = b.POLID
Or just to explain it simply see its simplified version
Select * from master m
outer apply (select top 4 * From Details d where m.Id = d.Id order by someColumns desc)o
I think we cannot use subquery as derived table in nhibernate. If you have suggestions, please share.
Thanks
I was keep working on this and found that it could be very difficult if want to do totally with QueryOver. I want to show how I did this.
First I took all the vendors with StockID to join with StockQuery later.
var stockVendors =
Session.QueryOver<Vendor>(() => V)
.Left.JoinQueryOver(p => V.Stock, () => sstk)
.Where(sstk.Number !=null)
.OrderBy(Projections.Max(() => V.TransactionDate)).Desc()
.ThenBy(() => sstk.Number).Asc()
.ThenBy(() => sv.Number).Asc()
.SelectList(
lst =>
lst.SelectGroup(() => V.Name).WithAlias(() => svhModal.VendorName)
.SelectGroup(() => V.Number).WithAlias(() => svhModal.VendorNumber)
.SelectGroup(() => sstk.Number).WithAlias(() => svhModal.StockNumber)
.Select(Projections.Max(() => V.TransactionDate)).WithAlias(() => svhModal.LastTransactionDate)
)
.TransformUsing(Transformers.AliasToBean()).List();
Then select Stock only
var stockDetail = Session.QueryOver<Stock>(() => stk)
.Where(soneCriteria)
.SelectList(list => list
.Select(() => stk.Id).WithAlias(() => sdrModal.Id)
.Select(() => stk.Number).WithAlias(() => sdrModal.Number)
.TransformUsing(Transformers.AliasToBean<StockDetailReportModal>())
.List<StockDetailReportModal>();
IList<StockVendor> vlst2 = null;
IList<StockDetail> newStock = new List<StockDetail>();
Here starts two loops to fill List object with each stock and its 5 top vendors from vendors list. Loop from Stockdetail result from query and inside loop from vendor result filtered to outer loop stockid, get first 5 vendors only in loop, when done just return the result to report. Its working fine.
foreach (StockDetail ostk in stockDetail)
{
stkid = ostk.Number;
vlst2 = (from v in stockVendors where v.StockNumber == stkid orderby v.LastTransactionDate descending select v).ToList<StockVendor>();
vndrcnt = 0;
stok = new StockDetail
{
Id = ostk.Id,
Number = ostk.Number,
//// other fields too here
};
if (vlst2.Count() == 0)
{
newStock.Add(stok);
}
foreach (StockVendor vn in vlst2)
{
if (vndrcnt == 0)
{
stok.VendorName = vn.VendorName;
stok.VendorNumber = vn.VendorNumber;
// other fields here...
newStock.Add(stok);
}
else
{
newStock.Add(new StockDetail
{
Id = ostk.Id,
Number = ostk.Number,
VendorName = vn.VendorName,
VendorNumber = vn.VendorNumber,
// adding vendor information in stock record.
});
}
vndrcnt++;
if (vndrcnt >= 4)
break;
}
This solved my problem and achieved this after investigating many days. You may find better approach, so please share.
Hi have two models (Rails3)
Aunt
Friends
Where
aunt :has_many => friends
and
friend :belongs_to => aunt
Now, I want to get all aunts that are not related to friend X
I tried something like:
Aunt.includes(:friends).where('friends.id != ? ', X )
But it doesn't work.
PS: I also need to include the aunts that don't have any friends associated.
This is the output of :
#results = Aunt.custom(true).select('aunts.id, aunts.goal').joins("LEFT OUTER JOIN friends r ON aunts.id = r.aunt_id").where('r.other_value != ? or r.id is NULL', 4259 ).ordered_by_status_creation.select('aunts.id, aunts.goal')
SELECT aunts.id, aunts.goal FROM aunts LEFT OUTER JOIN friends r ON
aunts.id = r.aunt_id WHERE aunts.deleted_at IS NULL AND
leads.type IN ('MyType') AND (is_custom = 1) AND (r.another_value
!= 4259 or r.id is NULL) ORDER BY status desc, aunts.id desc
Any ideas?
U can use scope as following
scope :without_house, lambda { |param| param ? {:conditions => ["related_id != ?", param.id]} : {} }
I think you need something like this:
Aunt.joins("LEFT OUTER JOIN friends ON aunts.id = friends.friend_id").where('friends.id != ? or friends.id is NULL', X ).select
I've got 2 entities, linked many-to-many. (Product & User)
I want to restrict Products by Users:
User userAlias = null;
query.JoinAlias(product => product.Users, () => userAlias)
.Where(() => userAlias.Id == currentUser.Id);
It's generated SQL code:
SELECT this_.Id as y0_
FROM [Product] this_
inner join UserToProduct users5_
on this_.Id = users5_.Product_id
inner join [User] useralias3_
on users5_.User_id = useralias3_.Id
....
In "Where" i use only user_id and i don't need second join.
How I can write the query(by QueryOver) with a single SQL join ?
This may help? I have a similar setup with UsersRoles
Role roleAlias = null;
var roles = _session.QueryOver<UsersRole>().JoinAlias(x => x.Role, () => roleAlias, JoinType.LeftOuterJoin).Where(
x => x.User.UserId == userId).List();
produces the following:
SELECT this_.UsersRolesId as UsersRol1_32_1_,
this_.UserId as UserId32_1_,
this_.RoleId as RoleId32_1_,
rolealias1_.RoleId as RoleId27_0_,
rolealias1_.RoleName as RoleName27_0_,
rolealias1_.Active as Active27_0_,
rolealias1_.DateCreated as DateCrea4_27_0_,
rolealias1_.LastUpdated as LastUpda5_27_0_,
rolealias1_.RoleSettingsId as RoleSett6_27_0_
FROM UsersRoles this_
left outer join Roles rolealias1_
on this_.RoleId = rolealias1_.RoleId
WHERE this_.UserId = 'a7eec4eb-21cc-4185-8847-a035010e779f' /* #p0 */
I have an odd relationship.
3 classes: Manager, Group, Vehicle
Group has a many to many to both Manager and Vehicle, but neither Manager nor Vehicle know anything about Group (only a one way mapping).
I have a ManagerID. I want to get a distinct list items of type T that has a VehicleID that is in a group that has a manager with the specified ID.
var vehicles = Session.QueryOver<Group>(() => group)
.Right.JoinQueryOver<Manager>(x => x.Managers)
.Where(x => x.Id == managerID)
.Select(Projections.Distinct(Projections.Property<VehicleGroup>(g => g.Vehicles)))
.List<Vehicle>()
;
Now what?
Ok, some further information:
"Manager" is not mapped to groups.
"Vehicle" is not mapped to groups.
Group has many Managers
Group has many Vehicles
A Manager can be referenced by multiple groups.
A Vehicle can be managed by multiple groups.
I have a Manager ID. I want to get a list of distinct Vehicle from the groups that have that manager.
============================================
Ok. More:
SQL I wish to emulate:
select * from Summary
where [vehicleID] in
(
select [vehicleID] from [Managers]
inner join [Manager_Groups] on [Managers].[managerID] = [Manager_Groups].[managerID]
inner join [Groups] on [Manager_Groups].[groupID] = [Groups].[groupID]
inner join [Groups_Object] on [Groups].[groupID] = [Groups_Object].[groupID]
inner join [Vehicle] on [Groups_Object].[ID] = [Vehicle].[vehicleId]
where [Managers].[ManagerId] = 34 and [Groups].[type] = 1
)
There are 2 types of groups. Drivers (type = 0) and vehicles (type = 1)
So far, I have:
var sq = QueryOver.Of<Manager>(() => manager)
.Where(mf => mf.Id == managerId)
.Fetch(mf => mf.ManagedVehicleGroups).Eager
.TransformUsing(Transformers.DistinctRootEntity)
.JoinQueryOver<VehicleGroup>(mf => mf.ManagedVehicleGroups)
.SelectList(list => list.Select(mf => mf.ManagedVehicleGroups))
;
var vp = Session.QueryOver<VehiclePerformanceDay>(() => item)
.WithSubquery.WhereExists(sq)
.Take(10)
.List();
And this generates:
SELECT
TOP (10) this_. ~~~lots of fields removed~~~
FROM
dbo.Summary this_
WHERE
exists (
SELECT
this_0_.ManagerId as y0_
FROM
dbo.Managers this_0_
inner join
dbo.Manager_Groups managedveh3_
on this_0_.ManagerId=managedveh3_.managerID
inner join
dbo.Groups vehiclegro1_
on managedveh3_.groupID=vehiclegro1_.groupId
WHERE
this_0_.ManagerId = 34
);
So, I am getting closer.
I think what you are after is somthing like the following.
var list = session.QueryOver<Group>()
.Where(x => x.Manager.Id == managerID)
.Select(group=> group.Vehicle)
.TransformUsing(Transformers.DistinctRootEntity)
.List<Vehicle>();
Ok - got a solution, mostly. Minor inconvenience that I will ask another question on:
var sq = QueryOver.Of<VehicleGroup>(() => vehicleGroup)
.JoinQueryOver<Manager>(vg => vg.Managers)
.Where(man => man.Id == managerId)
.JoinQueryOver<VehicleBase>(() => vehicleGroup.Vehicles)
.Where(v => v.Id == item.VehicleId)
.Select(vg => vg.Id)
;
var vp = Session.QueryOver<Summary>(() => item)
.WithSubquery.WhereExists(sq)
.Take(10)
.List();
So, this works. However, I had to add the map to Summary.VehicleId which is not what I wanted to do, but it'll do for now.
I have the following SQL query:
SELECT C.ID, C.Name FROM Category C JOIN Layout L ON C.ID = L.CategoryID
JOIN Position P ON L.PositionID LIKE '%' + CAST(P.ID AS VARCHAR) + '%'
WHERE P.Code = 'TopMenu'
and following data
Position:
ID Code
1 TopMenu
2 BottomMenu
Category
ID Name
1 Home
2 Contact
3 About
Layout
ID CategoryID PositionID
1 1 1
2 2 1,2
3 3 1,2
With the above data, is it possible to convert the SQL query to LINQ or Lambda expression?
Any help is appreciated!
This might do what you want:
Layout
.Where(x => Position
.Where(y => y.Code == "TopMenu")
.Select(y => SqlClient.SqlMethods.Like(x.PositionID, "%" + y.ID.ToString() + "%")
).Count() > 0
).Join(
Category,
x => x.CategoryID,
x => x.ID,
(o,i) => new { ID = i.ID, Name = i.Name }
)
Although you might want to materialize the 'Position' sub query to save on time like so:
var innerSubQuery = Position.Where(y => y.Code == "TopMenu");
Layout
.Where(x => innerSubQuery
.Select(y => SqlClient.SqlMethods.Like(x.PositionID, "%" + y.ID.ToString() + "%")
).Count() > 0
).Join(
Category,
x => x.CategoryID,
x => x.ID,
(o,i) => new { ID = i.ID, Name = i.Name }
);
I do, however, agree with Jon that to really make your life simpler you should change the way you're handling the many-to-many relationship by creating a 'Layout_Position' table.
Well, you won't be able to express the second join as a join, because it's not an equijoin, but this should do it:
from c in category
join l in layout on c.Id equals l.CategoryId
from p in position
where p.Id.Contains(l.PositionId)
select new { c.Id, c.Name };
Note that your "contains/LIKE" clause will give you bad results when you've got more than 9 positions. There are better approaches to many-to-many relations than using a comma-separated list. (Such as an intermediate table.)