How can I group the results of this query by wl.WishlistID?
var projected = (from wl in context.Wishlists.Where(x => x.UserId == 6013)
from wli in wl.WishlistItems
select new wishListProjection
{
wlId = wl.WishlistID,
wlUserId = (int)wl.UserId,
wlDesc = wl.description,
wlTitle = wl.Title,
wliWishlistItemID = wli.WishlistItemID,
wliQtyWanted = (int)wli.QtyWanted,
wliPriceWhenAdded = wli.PriceWhenAdded,
wliDateAdded = (DateTime)wli.DateAdded,
wliQtyBought = (int)wli.QtyBought,
}).ToList();
This returns the results I want, but I want to be able to iterate over them in the view without repeating the parent-level Wishlist object.
I've tried adding the line:
group wl by wl.WishlistID into g
But I don't seem to be able to access any properties by using g.[propertyname]
This grouping achieves more or less what I want, but I want to convert the results into a new or anonymous type, rather than return the entire object.
var results = context.WishlistItems.GroupBy(x => x.Wishlist).
Select(group => new { wl = group.Key, items = group.ToList() }).ToList();
You cannot access the properties of g because when you do the grouping:
group wl by wl.WishlistID into g
g is of type IGrouping<typeof(wl.WishlistID),typeof(wl)>, which is essentially a collection of all wl's with the same key wl.WishlistID. In other words, you cannot access the properties of g because g is not a single entity, it is a collection of those entities.
For your second grouping you said you would like to create an anonymous type instead of the entire object. You can do this by doing the selection first and then grouping:
var results = context.WishlistItems
.Select(x => new { })
.GroupBy(x => x.PropertyOfProjection)
.Select(group => new { wl = group.Key, items = group.ToList() }).ToList();
Or, using a nested sub query in your first example:
var projected = (from x in
(from wl in context.Wishlists.Where(x => x.UserId == 6013)
from wli in wl.WishlistItems
select new wishListProjection
{
wlId = wl.WishlistID,
wlUserId = (int)wl.UserId,
wlDesc = wl.description,
wlTitle = wl.Title,
wliWishlistItemID = wli.WishlistItemID,
wliQtyWanted = (int)wli.QtyWanted,
wliPriceWhenAdded = wli.PriceWhenAdded,
wliDateAdded = (DateTime)wli.DateAdded,
wliQtyBought = (int)wli.QtyBought,
})
group x by w.wlId into g).ToList();
I'm not sure what you mean by iterate without repeating the parent-level Wishlist object because whenever you create a grouping in Linq you will still have to have a nested foreach like:
foreach (var x in grouping)
{
x.Key;
foreach (var y in x)
{
y.Property;
}
}
Related
I have a situation where two tables should be joined with multiple columns with or condition. Here, I have a sample of sql query but i was not able to convert it into linq query.
select cm.* from Customer cm
inner join #temp tmp
on cm.CustomerCode = tmp.NewNLKNo or cm.OldAcNo = tmp.OldNLKNo
This is how i have write linq query
await (from cm in Context.CustomerMaster
join li in list.PortalCustomerDetailViewModel
on new { OldNLKNo = cm.OldAcNo, NewNLKNo = cm.CustomerCode } equals new { OldNLKNo = li.OldNLKNo, NewNLKNo = li.NewNLKNo }
select new CustomerInfoViewModel
{
CustomerId = cm.Id,
CustomerCode = cm.CustomerCode,
CustomerFullName = cm.CustomerFullName,
OldCustomerCode = cm.OldCustomerCode,
IsCorporateCustomer = cm.IsCorporateCustomer
}).ToListAsync();
But this query doesn't returns as expected. How do I convert this sql query into linq.
Thank you
You didn't tell if list.PortalCustomerDetailViewModel is some information in the database, or in your local process. It seems that this is in your local process, your query will have to transfer it to the database (maybe that is why it is Tmp in your SQL?)
Requirement: give me all properties of a CustomerMaster for all CustomerMasters where exists at least one PortalCustomerDetailViewModel where
customerMaster.CustomerCode == portalCustomerDetailViewModel.NewNLKNo
|| customerMaster.OldAcNo == portalCustomerDetailViewModel.OldNLKNo
You can't use a normal Join, because a Join works with an AND, you want to work with OR
What you could do, is Select all CustomerMasters where there is any PortalCustomerDetailViewModel that fulfills the provided OR:
I only transfer those properties of list.PortalCustomerDetailViewModel to the database that I need to use in the OR expression:
var checkProperties = list.PortalCustomerDetailViewModel
.Select(portalCustomerDetail => new
{
NewNlkNo = portalCustomerDetail.NewNlkNo,
OldNLKNo = portalCustomerDetail.OldNLKNo,
});
var result = dbContext.CustomerMasters.Where(customerMaster =>
checkProperties.Where(checkProperty =>
customerMaster.CustomerCode == checkProperty.NewNLKNo
|| customerMaster.OldAcNo == checkProperty.OldNLKNo)).Any()))
.Select(customerMaster => new CustomerInfoViewModel
{
Id = customerMaster.Id,
Name = customerMaster.Name,
...
});
In words: from each portalCustomerDetail in list.PortalCustomerDetailViewModel, extract the properties NewNKLNo and OldNLKNo.
Then from the table of CustomerMasters, keep only those customerMasters that have at least one portalCustomerDetail with the properties as described in the OR statement.
From every remaining CustomerMasters, create one new CustomerInfoViewModel containing properties ...
select cm.* from Customer cm
inner join #temp tmp
on cm.CustomerCode = tmp.NewNLKNo or cm.OldAcNo = tmp.OldNLKNo
You don't have to use the join syntax. Adding the predicates in a where clause could get the same result. Try to use the following code:
await (from cm in Context.CustomerMaster
from li in list.PortalCustomerDetailViewModel
where cm.CustomerCode == li.NewNLKNo || cm.OldAcNo = li.OldNLKNo
select new CustomerInfoViewModel
{
CustomerId = cm.Id,
CustomerCode = cm.CustomerCode,
CustomerFullName = cm.CustomerFullName,
OldCustomerCode = cm.OldCustomerCode,
IsCorporateCustomer = cm.IsCorporateCustomer
}).ToListAsync();
var result=_db.Customer
.groupjoin(_db.#temp ,jc=>jc.CustomerCode,c=> c.NewNLKNo,(jc,c)=>{jc,c=c.firstordefault()})
.groupjoin(_db.#temp ,jc2=>jc2.OldAcNo,c2=> c2.OldNLKNo,(jc2,c2)=>{jc2,c2=c2.firstordefault()})
.select(x=> new{
//as you want
}).distinct().tolist();
How can i dynamically change the selected columns in the generated sql query when using a linq expression?
Its a new session for each time the query is executed.
Even when I set the MapExp as null after first creation an then changing the bool value to false, it still generates the column in the sql query.
The code runs in a wpf application.
System.Linq.Expressions.Expression<Func<Entity, Model>> MapExp = x => new Model
{
Id=xId,
Count= LoadFormulaField ? x.Count: null,
...
};
var result = session.Query<Entity>().Select(MapExp))
Your problem seems to be the ternary-conditional as part of the expression which is causing the "Count" column to always be queried.
One option to avoid this could be:
var query = session.Query<Entity>();
IQueryable<Model> result = null;
if (LoadFormulaField)
{
result = query.Select(x => new Model
{
Id = x.Id,
Count = x.Count,
});
}
else
{
result = query.Select(x => new Model
{
Id = x.Id,
});
}
Which would get a little less ugly if you separate in a couple of methods I think.
I have 2 linq queries. First query does nothing because of unique index and this is OK. But second also does nothing while it should add records . If I bypass first query second query works. Should I refresh entity ? How ?
foreach (var product in productList)
{
cc2nexo_SubiektProduct newproduct = new cc2nexo_SubiektProduct();
newproduct.Name = product.Name;
newproduct.VAT = product.VAT;
newproduct.Id = product.Id;
foreach (var stawkaVAT in myNexo_ExitoEntities.StawkiVat)
{
if (stawkaVAT.Stawka * 100 == tryconvert_dec(newproduct.VAT))
{
newproduct.VAT_Id = stawkaVAT.Id;
}
}
myNexo_ExitoEntities.cc2nexo_SubiektProduct.Add(newproduct);
SurroundWithTryCatchDB(() =>
{
myNexo_ExitoEntities.SaveChanges();
});
}
var orders = (from myorders in myNexo_ExitoEntities.temp_SubiektOrderList
select myorders).ToList();
foreach (var order in orders)
{
cc2nexo_SubiektOrderList neworder = new cc2nexo_SubiektOrderList();
neworder.Data_utworzenia_sprawy = tryconvert_date(order.Data_utworzenia_sprawy);
neworder.Data_modyfikacji_sprawy = tryconvert_date(order.Data_modyfikacji_sprawy);
neworder.Data_umowy = tryconvert_date(order.Data_umowy);
neworder.Id = order.Id;
myNexo_ExitoEntities.cc2nexo_SubiektOrderList.Add(neworder);
SurroundWithTryCatchDB(() =>
{
myNexo_ExitoEntities.SaveChanges();
});
Debug.WriteLine(neworder.LastName);
}
I am receiving an error
Cannot insert duplicate key row in object 'dbo.cc2nexo_SubiektProduct' with unique index 'K_ID'. The duplicate key value is (1).The statement has been terminated
The reason of problem was SurroundWithTryCatchDB procedure not listed in my question. Because first query caused exception due to unique index all next SaveChanges did not work. I have changed my first query to work with unique values and now everything is OK.
How to convert the following sql query to lambda expression?
select cg.Code, ci.ChangeType, SUM(oc.Value) from OtherCharges oc
left join changeitems ci on oc.ChangeItemKey = ci.ChangeItemKey
left join ChangeGroups cg on ci.ChangeGroupKey = cg.ChangeGroupKey
where OtherKey = 'AB235A00-FEB2-4C4F-B0F9-3239FD127A8F'
group by cg.Code, ci.ChangeType
order by cg.Code, ci.ChangeType
Assuming you already have .NET domain types for your tables:
IQueryable<OtherCharges> otherCharges = ...
Guid otherKey = ...
var query = otherCharges.Where(oc => oc.OtherKey == otherKey)
.Select(oc => new { oc.ChangeItem, oc.Value })
.GroupBy(t => new { t.ChangeItem.ChangeGroup.Code, t.ChangeItem.ChangeType })
.OrderBy(g => g.Key.Code)
.ThenBy(g => g.Key.ChangeType)
// note that if Code is a non-nullable type you'll want to cast it to int? at some
// point so that when pulled into memory EF won't complain that you can't cast
// null to a non-nullable type. I expect that Code could sometimes be null here
// do to your use of LEFT OUTER JOIN in the T-SQL
.Select(g => new { g.Key.Code, g.Key.ChangeType, Sum = g.Sum(t => t.Value) });
var inMemoryResult = query.ToList();
Note that I'm using OtherCharge.ChangeItem and ChangeItem.ChangeGroup here. These are association properties and need to be set up as part of your model (e. g. using fluent configuration for EF code first).
I have the following query:
val = val.Select(item => new SimpleBill { CTime = item.CTime, Description = item.Description, ID = item.ID,
IDAccount = item.IDAccount, OrderNumber = item.OrderNumber, PSM = item.PSM, Sum = item.Sum,
Type = (BillType)item.Type,
ByteStatus = ((Bill)item).Payments.OrderByDescending(payment => payment.ID).FirstOrDefault().Status,
LastPaymentDate = ((Bill)item).Payments.OrderByDescending(payment => payment.ID).FirstOrDefault().CTime,
LastPaymentSum = ((Bill)item).Payments.OrderByDescending(payment => payment.ID).FirstOrDefault().Sum });
}
Is it possible to avoid repeating the ((Bill)item).Payments.OrderByDescending(payment => payment.ID).FirstOrDefault() part 3 times? I tried turning it into a method and into a delegate - the code compiled in both cases, but produced an exception at runtime.
You can use the let contstruct as follows:
val = from item in val
let lastPayment = ((Bill)item).Payments
.OrderByDescending(payment => payment.ID)
.FirstOrDefault()
select new SimpleBill
{
lastPayment.CTime,
//Rest of fields
}
However, as you may noticed this uses the LINQ Query syntax vs. Method syntax. IIRC let is only available in the former.