Can you make this Many to Many script more dynamic? - linq

This is just my simple way of making a many to many relationship, but i would like something that makes it easy to create many to many, I have wished i could make a method return type anonymous, that would open some doors. But i am noot good with anonymous types, Yet!
Hope you can help !
What do you guys do when you need
private class Ids
{
public int Id;
}
.
...
. And in some method:
IList<Ids> objIds = new List<Ids>();
var q = from c in dt.FK_Tags_Blogs
where c.BlogId == someId
select c.TagId;
foreach (var item in q)
{
objIds.Add(new Ids { Id = item });
}
var w = from c in objIds
join p in dt.Tags on c.Id equals p.Id
select p;
David B: I Used your code like this:
public static IQueryable<Tag> printTags(int id)
{
DataClassesDataContext dt = new DataClassesDataContext();
return
from b in dt.Blogs
where b.Id == id
from xr in b.FK_Tags_Blogs
select xr.Tag;
}
Is that stupid?

What I do is:
//linq to objects
IEnumerable<Tag> tags =
from c in dt.FK_Tags_Blogs
where c.BlogId == someId
join p in dt.Tags on c.TagId equals p.Id
select p;
//linq to sql with association properties
IQueryable<Tag> tagsQuery =
from b in dc.Blogs
where b.BlogId == someId
from xr in b.FK_Tags_Blogs
select xr.Tag;

Related

How can I define a List to add results of a query in a loop?

I have an array filled with long type values and for each value in the array I need to implement a query. I used foreach loop as you can see from the code below:
var result;
foreach(long id in PrdIdArr)
{
var mainQuery = (from o in db.OPERATIONs
join u in db.UNITs on o.OP_UNIT_ID equals u.UNIT_ID into smt
from s in smt
join x in db.XIDs on s.UNIT_ID equals x.UNIT_ID
where o.OP_OT_CODE == OtCode
where x.IDTYP_CD == "BSN"
where s.START_PRD_ID == id
where o.OP_UPD_DATE >= _StartDate
where o.OP_UPD_DATE <= _EndDate
select new
{
o.OP_ID,
o.OP_UPD_DATE,
x.EXTERNAL_ID,
o.OP_OS_CODE,
o.OP_START,
o.OP_ST_STATION,
s.START_PRD_ID
}).Take(_RowNumber);
//var result = mainQuery.ToList();
result.add(mainQuery.ToList());
}
data = this.Json(result);
data.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return data;
However, I have a problem in my code; I have to define a main list just before the foreach loop so that I could add results of each query to the that main list. my question is: How can I define this list as you can see at the beginning of my code? Thanks for the help...
How can I define this list as you can see at the beginning of my code?
Make
new {
o.OP_ID,
o.OP_UPD_DATE,
x.EXTERNAL_ID,
o.OP_OS_CODE,
o.OP_START,
o.OP_ST_STATION,
s.START_PRD_ID
}
into a concrete type (say QueryResult, although something a little more specific than that), and then just declare
var result = new List<QueryResult>();
Also, you should consider turning
foreach(long id in PrdIdArr)
and
where s.START_PRD_ID == id
into
where PrdIdArr.Contains(s.Start_PRD_ID)
var result = new List<object>();
foreach(long id in PrdIdArr)
{
....
result.Add(mainQuery.ToList());
}
You could do this:
var result = PrdIdArr.Select(id =>
from o in db.OPERATIONs
join u in db.UNITs on o.OP_UNIT_ID equals u.UNIT_ID into smt
from s in smt
join x in db.XIDs on s.UNIT_ID equals x.UNIT_ID
where o.OP_OT_CODE == OtCode
where x.IDTYP_CD == "BSN"
where s.START_PRD_ID == id
where o.OP_UPD_DATE >= _StartDate
where o.OP_UPD_DATE <= _EndDate
select new
{
o.OP_ID,
o.OP_UPD_DATE,
x.EXTERNAL_ID,
o.OP_OS_CODE,
o.OP_START,
o.OP_ST_STATION,
s.START_PRD_ID
}
.Take(_RowNumber)
.ToList()
).ToList();
I highly recommend performing some Extract Method refactorings, as the code is pretty complex and hard to understand/mange this way.
Just create the anonymous type outside with the same property names and the correct type
var result = Enumerable.Range(0, 0).Select(x => new
{
OP_ID = 1,
OP_UPD_DATE = DateTime.Now,
EXTERNAL_ID = 1,
OP_OS_CODE = 1,
OP_START = DateTIme.Now,
OP_ST_STATION = "",
START_PRD_ID = 1,
}).ToList();
And in your loop call AddRange
result.AddRange(mainQuery.ToList());

Doing 2 Left Joins on the same table with one call

I have the following tables:
Users:
userId, userFirstName, userLastName.
holdBilling:
bEntityID, CarrierOID, PayerOID, holdTYPE, createUserID.
carrier:
carrierOID, carrierName.
payer:
payerOID, payerName.
I want the code to save in a new entity
holdBilling => new
{
FirstName, LastName, CarrierName, PayerName
}
One of these Entities has either a payer or a carrier value (cannot have both). Basically i want to make 2 left joins on the same table with one call. This would be the SQL query that would work for me.
SELECT TOP 1000 [ID]
,[bEntityID]
,c.carrierID
,c.carrierName
,p.payerID
,p.payerName
,[holdType] ( this is "C" for carrier and "P" for payer )
FROM .[dbo].[holdBilling] hb
left join dbo.payer p on hb.payerID = p.payerID
left join dbo.carrier c on hb.carrierID = c.carrierID
where [bEntityID] = 378
The temporary solution I've found is getting a list of all Carriers
var listC = (from hold in holdBilling
join u in Users on hold.createUserID equals u.userID
join c in carrier.DefaultIfEmpty() on hold.carrierID equals c.carrierID
select new
{
Elem = hold,
FName = u.userFirstName,
LName = u.userLastName,
Carrier = c.carrierName,
Payer = ""
}).ToList();
and one for all payers
select new
{
Elem = hold,
FName = u.userFirstName,
LName = u.userLastName,
Carrier = "",
Payer = p.payerName
}).ToList();
and merging the two,I'm confident there has to be a solution for doing both in one query.
Something like this maybe:
var listC = (
from hb in holdBilling
from p in payer.Where(a=>a.payerID==hb.payerID).DefaultIfEmpty()
from c in carrier.Where(a=>a.carrierID=hb.carrierID).DefaultIfEmpty()
where hb.bEntityID==378
select new
{
hb.bEntityID,
c.carrierID,
c.carrierName,
p.payerID,
p.payerName,
holdType=(payer==null?"P":"C")
}
).Take(1000)
.ToList();
You need to use DefaultIfEmpty to do a left join
var listC = (from hold in holdBilling
from u in Users.Where(x => hold.createUserID == x.userID).DefaultIfEmpty()
from c in carrier.Where(x => hold.carrierID == x.carrierID).DefaultIfEmpty()
select new
{
Elem = hold,
FName = u.userFirstName,
LName = u.userLastName,
Carrier = c.carrierName,
Payer = ""
}).ToList();

Update class field in LINQ - is it possible?

I have 2 tables, and want to get records from 1 table and to "update" one of its fields from another table, and to pass final list of "Payment" objects somewhere. I cannot use anonymouse type, i need to get the list of proper typed objects.
There was a long way.
Got data:
var paymentsToShow = from p in paymentsRepository.Payments
join r in recordTypeRepository.RecordType
on p.RecordType equals r.Reference into p_r
where p.Customer == CustomerRef
from r in p_r.DefaultIfEmpty()
select new
{
Payment = p,
RecordType = r
};
var objList = paymentsToShow.ToList();
Change required field (basically, Payment.RecordTypeName is empty):
foreach (var obj in objList)
{
obj.Payment.RecordTypeName = obj.RecordType.Name;
}
Got list with correct type:
var paymentsList = from o in objList
select o.Payment;
Is there any way to get code shorter, to make required field update in the query or something else? I dont know where to look for.
I cannot change database.
You could do it like this:
var paymentsToShow = (from p in paymentsRepository.Payments
join r in recordTypeRepository.RecordType
on p.RecordType equals r.Reference into p_r
where p.Customer == CustomerRef
from r in p_r.DefaultIfEmpty()
select new
{
Payment = p,
RecordType = r
}).Select(x =>
{
x.Payment.RecordTypeName = x.RecordType.Name;
return x.Payment;
});
This will result in an IEnumerable<Payment>, so no anonymous type used.

How to return specific list result from linq to entities

Hi Experts
I currenly write this code:
public IList<TResult> GetCustomQuery<TResult>(int orderID, Func<Order, TResult> selector)
{
using(RepositoryDataContext = new NorthwindEntities())
{
IList<TResult> res = (from od in RepositoryDataContext.Order_Details
join o in RepositoryDataContext.Orders
on od.OrderID equals o.OrderID
join p in RepositoryDataContext.Products
on od.ProductID equals p.ProductID
join c in RepositoryDataContext.Customers
on o.CustomerID equals c.CustomerID
where o.OrderID > orderID
select new
{
o.OrderID,
od.UnitPrice,
od.Quantity,
p.ProductName,
c.CompanyName
}).Select<Order, TResult>(selector).ToList();
}
}
I want to return result of my linq to entities in specific format(TResult).
writing this code using Lambda Expression is hard because of joins.
this line has exception :Select < Order, TResult > (selector)
how I can Fix that?
thanks
Instead of creating an Anonymous type, create a POCO or in your case an Order
select new Order()
{
OrderProperty1 = o.OrderID,
OrderProperty2 = od.UnitPrice,
OrderProperty3 = od.Quantity,
OrderProperty4 = p.ProductName,
OrderProperty5 = c.CompanyName
}).Select<Order, TResult>(selector).ToList();
In your second last line: Try to call ToList() before the Select(). Like this:
}).ToList().Select<Order, TResult>(selector);
Is it possible Iterate "res" and return a list of TResult?

LINQ to pull back object graph

Is it possible to group by more than one group in LINQ?
For instance, I have this query (obviously incomplete)
from lxr in LOCATION_XREFs
join l in LOCATIONs on lxr.LOCATION_SKEY equals l.LOCATION_SKEY
join c in COMPANies on l.COMPANY_SKEY equals c.COMPANY_SKEY
join prlx in PeopleRoleLocationXrefs on lxr.LOCATION_XREF_SKEY equals prlx.LOCATION_XREF_SKEY
join p in PEOPLEs on prlx.PEOPLE_SKEY equals p.PEOPLE_SKEY
join pr in PeopleRoles on prlx.PeopleRoleKey equals pr.PeopleRoleKey
... and I'd like to get back a bunch of companies that have a bunch of locations that, in turn, have a bunch of people.
If you're looking to group by multiple parameters, that is possible:
from lxr in LOCATION_XREFs
join l in LOCATIONs on lxr.LOCATION_SKEY equals l.LOCATION_SKEY
join c in COMPANies on l.COMPANY_SKEY equals c.COMPANY_SKEY
join prlx in PeopleRoleLocationXrefs on lxr.LOCATION_XREF_SKEY equals prlx.LOCATION_XREF_SKEY
join p in PEOPLEs on prlx.PEOPLE_SKEY equals p.PEOPLE_SKEY
join pr in PeopleRoles on prlx.PeopleRoleKey equals pr.PeopleRoleKey
group c by new { c.COMPANY_SKEY, l.LOCATION_SKEY} into myGroup
select new
{
myGroup.Key.COMPANY_SKEY,
myGroup.Key.LOCATION_SKEY,
myGroup.Count()
}
I ultimately used the following code to achieve what I wanted. Interesting note: notice that I wanted the Roles flattened out and concatenated with commas, so I did this using a wrapper accessor that uses the Aggregate operator. Apparently the Aggregate operator is not suuported within a LINQ query, as you get "the query operator "Aggregate" is not supported" otherwise I would have done it right there inline like this Roles = new List<string>(g.Select(u => u.pr.RoleName)).Aggregate((a, b) => a + ", " + b)
public class DAOPerson
{
public string Name { get; set; }
public int PeopleSkey { get; set; }
public List<string> RolesCollection { get; set; }
public string Roles
{
get { return RolesCollection.Aggregate((a, b) => a + ", " + b); }
}
}
IQueryable<DAOLocation> gridData;
gridData = (from lxr in db.LOCATION_XREFs
join l in db.LOCATIONs on lxr.LOCATION_SKEY equals l.LOCATION_SKEY
join c in db.COMPANies on l.COMPANY_SKEY equals c.COMPANY_SKEY
where lxr.DEPARTMENT_NUMBER == Department.BINDING_AUTHORITY_KEY
&& lxr.BRANCH_NUMBER == Branch.ATLANTAKEY
orderby c.NAME, l.INTERNAL_NAME ascending
select new DAOLocation
{
CompanyName = c.NAME,
CompanySkey = c.COMPANY_SKEY,
LocationName = l.INTERNAL_NAME,
LocationSkey = l.LOCATION_SKEY,
Persons = (from prlx in db.PeopleRoleLocationXrefs
join lxr2 in db.LOCATION_XREFs on prlx.LOCATION_XREF_SKEY equals lxr.LOCATION_XREF_SKEY
join p in db.PEOPLEs on prlx.PEOPLE_SKEY equals p.PEOPLE_SKEY
join pr in db.PeopleRoles on prlx.PeopleRoleKey equals pr.PeopleRoleKey
where lxr2.LOCATION_SKEY == l.LOCATION_SKEY
group new { p, pr } by p.PEOPLE_SKEY into g
select new DAOPerson
{
Name = g.First().p.LAST_NAME,
PeopleSkey = g.First().p.PEOPLE_SKEY,
RolesCollection = new List<string>(g.Select(u => u.pr.RoleName))
}).ToList()
});

Resources