Linq Best way to Set the inner property - c#

I am trying to pull the results from the database and set the child property while selecting using the Linq (EF V5.0). The reason I am doing this is because there is no relation in the database to use include..
var lamdaResult = from u in model.Entity_Users
join s in model.Entity_Staff on u.UserID equals s.ST_UserID
select new { u, s };
return lamdaResult.Select(x => x.u.Staff = x.s; return x.u;).FirstOrDefault();
I am learning Linq.. the above expression is giving me error.. can someone help me the best way to set the child property...
I could also do this.. but I am wondering is there any better way to fulfill the same result instead of following 2 expressions
var user=null;
var lamdaResult = from u in model.Entity_Users
join s in model.Entity_Staff on u.UserID equals s.ST_UserID
select new { u, s };
user = lamdaResult.Select(x => x.u).FirstOrDefault();
user.Staff = lamdaResult.Select(x => x.s).FirstOrDefault();

Linq is for querying, not for mutating objects. You'll need to use something other than LINQ to do the mutation, generally a foreach is appropriate, although given that you only have a single item, there's no need for even that:
var item = (from u in model.Entity_Users
join s in model.Entity_Staff on u.UserID equals s.ST_UserID
select new { User = u, Staff = s })
.FirstOrDefault();
item.User.Staff = item.Staff;
return item.User;

Related

LINQ select new with collection

Context
I am trying to get a list from select new:
var portfolioresult =
(from port in _context.Portfolio
join u in _context.Universe on port.CUSIP equals u.ID_CUSIP
join m in _context.MarketDataEvent on u.ID_CUSIP equals m.CUSIP_NUMBER_REALTIME
//select new { m, port.Name }).ToList();
select new ViewResult() { MarketDataEvents = m, PortfolioName = port.Name })
.ToList();
I want to get MarketDataEvents as List<MarketDataEvent>
Corresponding SQL query
SELECT me.*, p.Name FROM MarketDataEvent me
INNER JOIN universe u ON u.ID_CUSIP=me.CUSIP_NUMBER_REALTIME
INNER JOIN portfolio p ON p.CUSIp=me.CUSIP_NUMBER_REALTIME
Problem
I am not able to get a List inside select new. Is it possible to get something like this?
select new ViewResult() { MarketDataEvents = List<MarketDataEvents>, PortfolioName = port.Name })
Expected result
List<MarketDataEvents> "XYZ"
List<MarketDataEvents> "ABC"
Actual result
MarketDataEvent "XYZ
MarketDataEvent "XYZ"
MarketDataEvent "ABC"
Yes, it is possible:
var query =
from port in _context.Portfolio
select new ViewResult
{
MarketDataEvents =
(from u in _context.Universe.Where(u => port.CUSIP == u.ID_CUSIP)
join m in _context.MarketDataEvent on u.ID_CUSIP equals m.CUSIP_NUMBER_REALTIME
select m).ToList(),
PortfolioName = port.Name
};
var portfolioresult = query.ToList();
Essentially your m reference is out of scope. The input available to a select statement is only a single value out of the set available as a result of the select/joins you're looking at, which is why you don't see a list of all available from m, only a single value in each record.
Rather, you need to use a SelectMany since it'll expose an IEnumerable as the input to the function and you can split out the individual XYZ values out of that.

Linq to Sql - How to get data from second level table

I'm newbie to linq to sql, just trying to understand what type of queries I can handle with linq.
Here is my database scheme,
I want to get all customers of a specific user and this is what I've done,
var userId = 4;
var companies = from c in db.Company
where c.UserId == userId
select c.Id;
var costumers = from c in db.Customers
where companies.Contains(c.CompanyId)
select c;
I'm just wondering whether it's a nice approach and is there any better method to handle this type of queries?
Use can also get customers by this way also:
var result = db.Customers.Join(
db.Company, customer => customer.CompanyId, comp => comp.Id, (customer, comp)
=> new { customer, comp }).Where(#t => #t.comp.UserId == 4)
.Select(#t => #t.customer);
You can also keep it simple like this.
select * from db.Customers Cus
inner join db.company Com on Com.Id = Cus.CompanyId
where Com.UserId= userId
Contains is the equivalent of IN in SQL and your Linq statement will be translated to a SQL statement. So I can't really see another way that will give you better performance with Linq. If you want to use less code you can maybe try the following instead:
var companies = db.Companies.Where(x=> x.UserId == userid).Select(x=>x.Id);
var customers = db.Customers.Where(x=> companies.Contains(x.CompanyId));

SharpRepository - Join Between Two Repositories

I have scoured the net and was unable to find any example of conducting a join between two SharpRepository repos. Can anyone provide a link to a page or an example? I am attempting to conver the following linq expression into a sharp repo expression:
var user = (from f in _context.AccountUsers
join h in _context.Users on f.UserId equals h.UserId
where f.AccountId == accountId && h.UserName.Contains(email)
select new
{
h
});
return (IEnumerable<User>)user;
----- UPDATE ------
This is what I came up with, but it doesn't seem to be working propertly...
var aur = new AccountUserRepository();
var user = this.Join(aur, u => u.UserName.Contains(email), au => au.AccountId == accountId,
(u, au)=> u).AsQueryable().AsEnumerable();
return user;
There is a Join method on the repository that is similar to a LINQ Join statement and will let you join one IRepository<> with another IRepository<>. You pass it an IRepository<> to join with, an inner key selector, an outer key selector and a result selector.
You can look here for an integration test that uses it: https://github.com/SharpRepository/SharpRepository/blob/master/SharpRepository.Tests.Integration/RepositoryJoinTests.cs
The result of this call is another repository that you can then call GetAll, or FindAll, etc. on just like it was a normal IRepository<> itself. So I think you'll want to do something like this:
var accountUserRepo = new AccountUserRepository();
var userRepo = new UserRepository();
// join on the UserId column that is common to both, and select an anonymous type with both pieces of info (you would select just what you need)
var compositeRepo = accountUserRepo.Join(userRepo, au => au.UserId, u => u.UserId, (au, u) => new { AccountUserInfo = au, UserInfo = u } );
return compositeRepo.FindAll(x => UserInfo.UserName.Contains(email) && x.AccountInfo.AccountId == accountId, x => x.UserInfo);
That is how I think you would do it with the Join syntax.
If you have navigation properties like you would in EF you could probably just do this syntax which is simpler:
return accountUserRepo.FindAll(x => x.AccountId == accountId && x.User.UserName.Contains(email), x => x.User);

dynamic linq group by clause

I have multiple linq queries that retrieve the same data just at different grouping levels. (potentially 3 different levels). The linq query currently results in an enumerable list of a custom object. The items I don't understand or wonder if possible (to reduce redundant code):
can I make the following group by clause to be dynamic?
if so, can it dynamically populate my custom object group data when it is grouped at that level.
For instance:
var myReport_GroupProductLevel =
from r in mySum_GroupProductLevel
join pc in _myPlotCount on r.Strata equals pc.Strata
join acr in _myStrataAcres on pc.Strata equals acr.Strata
group new { r, pc, acr } by new { r.Strata, pc.Count, acr.Acres, r.GroupName, r.ProductName } into g
select new DataSummary
{
Strata = g.Key.Strata,
PlotCount = g.Key.Count,
Acres = g.Key.Acres,
ClassName = string.Empty,
GroupName = g.Key.GroupName,
ProductName = g.Key.ProductName,
TPAMEAN = g.Sum(x => x.r.TPA / x.pc.Count),
TPADEV = g.Select(x => x.r.TPA).StdDev(g.Key.Count)
};
If I wanted to group only by "GroupName" instead... I would rewrite the query. Issues I see are, if I'm grouping by a value then I need that value in the query (g.Key.GroupName); but since I'm creating a new custom object the other non-grouped values such as "ClassName" require a value (I used string.Empty above, but that is static).
Thanks for any insight...
if anyone was curious, I got it to work by using a conditional statement... since grouping by empty will make it collapse.
var mySum_ClassGroupProductLevel =
from s in ReportData.myStands
join p in ReportData.myPlots on s.ID equals p.StandID
join t in ReportData.myTrees on p.ID equals t.PlotID
group t by new { s.Strata, p.ID,
ClassName = useClassName ? t.ClassName : string.Empty,
GroupName = useGroupName ? t.GroupName : string.Empty,
ProductName = useProductName ? t.ProductName : string.Empty }
into g
select new
{}

Help with LINQ query

I currently a list of a Supplier class, within that supplier class is a list of orders.
Each order has a userID and an empty string variable for username.
I then have a list of users which contains userID and username.
The way I am doing this now is:
foreach(supplier s in SupplierList)
{
foreach (order o in s.childorders)
{
user u = _users.First(p => p.userid == o.userid);
o.username = u.username;
}
}
I feel this might be a little inefficient and I was wondering if it is possible to compact it down into one linq query?
The logic should be
set supplierslist.childorders.username to the value in _users where supplierslist.childorders.userid == _users.userid.
Im fairly new to Linq so any advice for this would be apreciated, or also if its a bad idea and to leave it as it is / reasons why would be good too.
Thanks
What you want to do here is iterate over a collection (many collections, really, but it doesn't make a difference) and mutate its members. LINQ is not really targeted at performing mutating operations but rather at querying. You can do it with LINQ, but it's against the spirit of the tool.
If you are constructing the SupplierList yourself, it might be possible to fetch the data appropriately with LINQ so that it comes pre-populated as you want it to be.
Otherwise, I 'd leave the foreach as it is. You can make a dictionary that maps ids to users to make the inner loop faster, but that's your call and it depends on your data size.
var orderUserPairs = SupplierList
.SelectMany(s => s.ChildOrders)
.Join(_users, o => o.UserId, u => u.userId, (Order, User) => new {Order, User});
foreach (var orderUserPair in orderUserPairs)
orderUserPair.Order.username = orderUserPair.User.username;
Though having both username and userId as part of order looks suspicious.
First a question...
It looks like you are operating on every order. Why do you need to cycle through the supplierlist first since you don't seem to be using it inside the loop? Unless there are orders that don't belong to any supplierlist, you might be able to skip that step.
If that isn't the case, then I think you can use a join. If you aren't familiar with the syntax for joins in linq, this is one (simplified) way to approach it:
var x = from S in SupplierList
join C in childorders on C.supplierlistID equals S.ID
where [whatever you need here if anything]
select new { field1, field2};
foreach var y in x
{
}
Note I assumed a foreign key in childorders to supplierlist. If that isn't the case you will have to modify accordingly.
Hope that helps.
You need to use SelectMany or join depending on weather you are using linq-to-sql or linq with local collections. If you are using local collections the better way is to use join, else use SelectMany.
Like this...join:
var selection = (from s in SupplierList
join o in s.childholders on s.userid equals o.userid
select new { username = o.username);
or, in case of linq-to-sql:
var selection = (from s in SupplierList
from o in s.childholders
select { username = o.username);
You can then use the anonymous type you projected the way you want.
I agree with Jon, but you could say:
var orders = (from s in supplier
from o in s.childorders
select new
{
Order = o,
User = _users.First(p => p.userid == o.userid)
}).ToList();
foreach(var order in orders) {
order.Order.username = order.User.username;
}
Untested of course :)
If users list contains many elements, it can be really slow so I'd use a temporary dictionary:
var userById = users.GroupBy(x => x.userid)
.ToDictionary(x => x.Key, x => x.First());
foreach(var order in supplier.SelectMany(x => x.childorders))
{
order.username = userById[order.userid].username;
}

Categories

Resources