Where In with nHibernate using InExpression - c#

Having a really hard time trying to figure out a "where in" equivalent in nHibernate.
I am using nHibernate 3. What's the best way to do something like this:
SELECT DISTINCT
U.ID as CID
FROM User U
WHERE
CID IN (
SELECT RID
FROM ResellerSites rs
INNER JOIN Locations l ON l.ID = rs.LID
WHERE l.ID = 14
)
I found an examples somewhere that says I need to have something like this:
var criteria = session.CreateCriteria(typeof(User));
var resellerSites = new[] { new ResellerSite { Id = 1 }, new ResellerSite { Id = 2 } };
criteria.Add(new InExpression("ResellerSite", resellerSites));
This is what I have so far:
var resellerSites = session.CreateCriteria<ResellerSite>("p")
.CreateCriteria("p.Locations", JoinType.InnerJoin)
.Add(Restrictions.Eq("locationID", locationId))
.List<ResellerSite>();
criteria.Add(new InExpression("ResellerSite", resellerSites));
var finalList = criteria.List<ResellerSite>();
The "criteria.Add(new InExpression" part is giving me an intellisense error, as InExpression seems to expect something like:
new[] { new ResellerSite { Id = 1 }, new ResellerSite { Id = 2 } };
Like in the first example.
Should I do a for loop like:
foreach (var site in resellerSites)
{
//somehow push into a new[] ?
}
or something like that or is there a better way?
Perhaps this entire approach is wrong?

I'd say that the typing problem comes from the double CreateCriteria and the single ToList()
Difficult to say without the table definitions, but, rereading you code, I wonder why you need the inner join with the locations.
May be you can rewrite your query as :
SELECT DISTINCT
U.ID as CID
FROM User U
INNER JOIN ResellerSites rs
on U.ID = rs.RID
and rs.LID=14
And have your code like (not tested and not optimal as you could have only one criteria query with join)
var resellerSites = session.CreateCriteria<ResellerSite>()
.Add(Expression.Eq("locationID", locationId))
.List<ResellerSite>();
criteria.Add(new InExpression("ResellerSite", resellerSites.ToArray()));
var finalList = criteria.List<ResellerSite>();

You can easily convert resellerSites to array using Linq:
criteria.Add(new InExpression("ResellerSite", resellerSites.ToArray()));
Also this question may help: Cannot use collections with InExpression

Related

whats the fastest way to write join in linq

I have 2 classes user(count-10k),address(count-1million). these are like one to many.
i am trying to map the address for users.
Using List(takes few minutes):
List<User> us = usrs.Select(u => new User { id = u.id ,email=u.email,name=u.name,addresses=adrs.Where(a=>a.userid==u.id).ToList()}).ToList();
the above works but its very slow
i changed it to use dictionary and its fast.
Using Dictionary(takes few seconds):
var dusrs = usrs.ToDictionary(usr => usr.id);
var daddrs = adrs.ToDictionary(adr => Tuple.Create(adr.id,adr.userid));
foreach (var addr in daddrs)
{
var usr = dusrs[addr.Value.userid];
if (usr.addresses == null)
{
usr.addresses = new List<Address>();
}
usr.addresses.Add(addr.Value);
}
is there any way i can write better query using list rather than dictionary?
I am just trying to see if i can write better linq using lists
thanks...
vamsee
Assuming you are keeping users and addresses in Lists for some reason, you can use a join in LINQ which will combine the two lists and use a hashed data structure internally to put them together:
var us2 = (from u in usrs
join a in adrs on u.id equals a.userid into aj
select new User { id = u.id, email = u.email, name = u.name, addresses = aj.Select(a => a).ToList() }).ToList();
Alternatively, you can convert the addresses into a Lookup and use that, but it would probably be best to just keep the addresses in a Lookup or create them in a Lookup initially if possible:
var addressLookup = adrs.ToLookup(a => a.userid);
List<User> us = usrs.Select(u => new User { id = u.id, email=u.email, name=u.name, addresses=addressLookup[u.id].ToList() }).ToList();
In my test cases which is faster seems to depend on how many users versus addresses match.

Unioning two LINQ queries

I just need to make full outer join with Linq, But When i union two quires i get this error:
Instance argument: cannot convert from 'System.Linq.IQueryable' to 'System.Linq.ParallelQuery
And here is my full Code:
using (GoodDataBaseEntities con = new GoodDataBaseEntities())
{
var LeftOuterJoin = from MyCustomer in con.Customer
join MyAddress in con.Address
on MyCustomer.CustomerId equals MyAddress.CustomerID into gr
from g in gr.DefaultIfEmpty()
select new { MyCustomer.CustomerId, MyCustomer.Name, g.Address1 };
var RightOuterJoin = from MyAddress in con.Address
join MyCustomer in con.Customer
on MyAddress.CustomerID equals MyCustomer.CustomerId into gr
from g in gr.DefaultIfEmpty()
select new { MyAddress.Address1, g.Name };
var FullOuterJoin = LeftOuterJoin.Union(RightOuterJoin);
IEnumerable myList = FullOuterJoin.ToList();
GridView1.DataSource = myList;
GridView1.DataBind();
}
The types of your two sequences are not the same, so you can't do a Union.
new { MyCustomer.CustomerId, MyCustomer.Name, g.Address1 };
new { MyAddress.Address1, g.Name };
Try making sure that the fields have the same names and types in the same order.
Why not select it all as one thing? Depending on your setup (i.e., if you have foreign keys properly set up on your tables), you shouldn't need to do explicit joins:
var fullJoin = from MyCustomer in con.Customer
select new {
MyCustomer.CustomerId,
MyCustomer.Name,
MyCustomer.Address.Address1,
MyCustomer.Address.Name
};
Method syntax:
var fullJoin = con.Customers.Select(x => new
{
x.CustomerId,
x.Name,
x.Address.Address1,
x.Address.Name
});
union appends items from one collection to the end of another collection, so if each collection had 5 items, the new collection will have 10 items.
What you seem to want is to end up with 5 rows with more infomration is each. That's not a job for Union. You might be able to do it with Zip(), but you'll really be best with the single query as shown by DLeh.

Convert My Code SQL to LINQ?

Kindly convert my SQL to LINQ. I'm really desperate. It includes multiple filtering (2).
SELECT dbo.EmployeeAccess.EmpNo,
dbo.View_SystemAdminMembers.LNameByFName,
dbo.View_SystemAdminMembers.GroupName,
dbo.View_SystemAdminMembers.Role,
dbo.View_SystemAdminMembers.Active,
dbo.View_SystemAdminMembers.EmpNo AS Expr4,
dbo.View_SystemAdminMembers.RoleID
FROM dbo.EmployeeAccess
INNER JOIN dbo.View_SystemAdminMembers
ON dbo.EmployeeAccess.GroupID = dbo.View_SystemAdminMembers.GroupID
WHERE (dbo.EmployeeAccess.EmpNo = '50')
Thank you so much in advance.
Please try with the below code snippet.
var result =from e in context.EmployeeAccess
join v in context.View_SystemAdminMembers on e.GroupID equals v.GroupID
Where e.EmpNo == 50
select new { e.EmpNo,v.LNameByFName,v.GroupName,v.Role,v.Active,a.RoleID,v.EmpNo as VEmpNo };
Note : context is your DB Context object.
Let me know if any concern.
var results = (from ea in DbContext.EmployeeAccess
join sam in DbContext.View_SystemAdminMembers on ea.GroupId equals sam.GroupId
where ea.EmpNo = '50'
select new {
ea.EmpNo,
sam.LNameByFName,
sam.GroupName,
sam.Role,
sam.Active,
Expr4 = sam.EmpNo,
sam.RoleID
};
You didnt mention what your database context was, you'll have to fill that in yourself.
var res = (from x in ctx.EmployeeAccess
join y in ctx.View_SystemAdminMembers on x.GroupId equals y.groupId
where x.EmpNo = '50'
select new
{
x.EmpNo,
y.LNameByFName,
y.GroupName,
y.Role,
y.Active,
Expr4 = y.EmpNo,
y.RoleID
});
Note: do NOT use = when joining, but equals.

Getting DISTINCT values from a JOIN

i currently have the following LINQ statement:
using (MYEntities ctx = CommonMY.GetMYContext())
{
List<datUser> lstC = (from cObj in ctx.datUser
join fs in ctx.datFS on cObj.UserID equals fs.datUser.UserID
where userOrg.Contains(fs.userOrg.OrgName)
select cObj).ToList();
foreach (datUser c in lstC)
{
Claim x = new Claim
{
UserID= c.userID,
FirstName = c.FirstName,
LastName = c.LastName,
MiddleName = c.MiddleName,
};
}
}
right now it returns all users, but it duplicates them if they have more then 1 org associated with them.
how can i ensure that it only returns distinct UserIDs?
each user can have multiple orgs, but i really just need to return users that have at least 1 org from the userOrg list.
Right before your ToList, put in .Distinct().
In response to #DJ BURB, you should probably use the Distinct overload that takes in an IEqualityComparer to best be sure that you're doing it based off of the unique id of each record.
Look at this blog post for an example.
use group by.
syntax:
var result= from p in <any collection> group p by p.<property/attribute> into grps
select new
{
Key=grps.Key,
Value=grps
}
You will have to call Distinct(), there is no linq query equivalent of that command.

Help troubleshooting LINQ query

I have this LINQ query:
var returnList = from TblItemEntity item in itemList
join TblClientEntity client in clientList
on item.ClientNo equals client.ClientNumber
join TblJobEntity job in jobList
on item.JobNo equals job.JobNo
where item.ClientNo == txtSearchBox.Text //Is this filter wrong?
orderby client.CompanyName
select new { FileId = item.FileId, CompanyName = client.CompanyName, LoanStatus = item.LoanStatus, JobNo = job.JobNo, JobFinancialYE = job.JobFinancialYE, VolumeNo = item.VolumeNo };
Why doesn't this return anything?
P/S : All of them are of string datatype.
Have you tried to remove parts of the join to figure out where the problem is and then add those removed parts back again one after one? Start with:
var returnList = from TblItemEntity item in itemList
where item.ClientNo == txtSearchBox.Text //Is this filter wrong?
select new { FileId = item.FileId };
Since you're doing inner joins there could be that one of the joins filters out all the items.
EDIT: When debugging don't expand the return type, the select new {FileId = item.FileId} is all you need to debug.
Still waiting on that sample data.
You say you're getting results filtering by other attributes so why should this be any different? Assuming the user-input txtSearchBox has a reasonable value, try printing the values out onto the debug console and see if you're getting reasonable results. Look at the output window. Try this version of your query:
Func<string,bool> equalsSearch = s =>
{
var res = s == txtSearchBox.Text;
Debug.WriteLine("\"{0}\" == \"{1}\" ({2})", s, txtSearchBox.Text, res);
return res;
};
var returnList = from TblItemEntity item in itemList
join TblClientEntity client in clientList
on item.ClientNo equals client.ClientNumber
join TblJobEntity job in jobList
on item.JobNo equals job.JobNo
//where item.ClientNo == txtSearchBox.Text //Is this filter wrong?
where equalsSearch(item.ClientNo) //use our debug filter
orderby client.CompanyName
select new { FileId = item.FileId, CompanyName = client.CompanyName, LoanStatus = item.LoanStatus, JobNo = job.JobNo, JobFinancialYE = job.JobFinancialYE, VolumeNo = item.VolumeNo };
Why doesn't this return anything?
There two possibilites:
1) The join is empty, that is, no items, clients and jobs have matching ID's.
2) The where clause is false for all records in the join.
To troubleshoot this you will have to remove the where clause and/or some of the joined tables to see what it takes to get any results.

Categories