I have a linq query where I am trying to select the name of the user if (s)he has a spesific role. But I want it to be selected, if and only if (s)he has only the targeted spesific role, not with the other spesified roles(such as General Manager and Purchase Manager).
DepartmentManagerName = (from r in efDB.TBL_TABNET_REL_USER_ROLE
where (h.Confirm_By == r.TBL_USER.ID) && r.TBL_TABNET_DEF_ROLE.ID == (int)Enums.UserRank.Manager
select r.TBL_USER.Name + " " + r.TBL_USER.Surname).FirstOrDefault(),
One user can have multiple roles in the table, such as being "Department Manager" and "General Manager" together. Here is the example from the table TBL_TABNET_DEF_ROLE;
ID UserID RoleID
123 40 2
126 40 5
127 36 2
128 42 2
129 49 2
130 55 2
131 59 2
132 61 2
133 76 2
134 77 2
But when I am assigning to the DepartmentManagerName variable, I don't want it to be assigned if the user has also the "General Manager" role. Because of the reason "Department Manager" role comes earlier than "General Manager" role in the database table, the where condition is being true and the user name is assigned to DepartmentManagerName variable even in next iterations it will be identified that user also has the role of "General Manager". But I want to achieve that there will be no assignment if any other role matched other than "Department Manager". How could I achieve that?
I think of something like this to solve your problem, it will get the UserId of the first user that have only one role and the RoleId == 2 (in my example).
public static void Main()
{
var table = new List<TBL_USER>
{
new TBL_USER(1, 1, 1),
new TBL_USER(2, 1, 2),
new TBL_USER(3, 2, 1),
new TBL_USER(5, 4, 1),
new TBL_USER(6, 4, 2),
new TBL_USER(7, 5, 1),
new TBL_USER(8, 5, 2),
new TBL_USER(9, 5, 3)
};
var user = table
.GroupBy(tbl => tbl.UserId) // Group the lines with the same UserId
.Where(grp => grp.Any(u => u.RoleId == 1) && grp.All(u => u.RoleId != 2)) // Get the groups that have a RoleId as 1 and not RoleId as 2
.FirstOrDefault().Key; // Get the first group and get the Key (UserId)
}
public class TBL_USER
{
public int Id { get; set; }
public int UserId { get; set; }
public int RoleId { get; set; }
public TBL_USER(int id, int user, int role)
{
Id = id;
UserId = user;
RoleId = role;
}
}
Related
I have the following collection Model: Hotel
public class Hotel {
int HotelId {get;set;}
decimal Price {get;set;}
int vendorId {get;set;}
int vendorHotelId {get;set;}
}
The records will be like this
HotelId Price VendorId VendorHotelId
1 100 1 0
2 200 2 0
3 300 1 0
4 400 2 1
If the VendorHotelId is equal to HotelId then I need to select the record which has the cheapest price in LINQ.
I want the result like this
HotelId Price VendorId VendorHotelId
1 100 1 0
2 200 2 0
3 300 1 0
Can anyone help me to solve this query?
You can use a conditional expression to group based on your condition, then get the minimum price from each group, which will be the one hotel if no matching vendorHotelId exists.
var ans = (from h in hotels
let hasVendor = h.vendorHotelId > 0
group h by hasVendor ? h.vendorHotelId : h.HotelId into hg
let hmin = hg.OrderBy(h => h.Price).First()
select new {
HotelId = hmin.HotelId,
Price = hmin.Price,
vendorId = hmin.vendorId
})
.ToList();
Update: Since you seem to be using fluent syntax based on your comment, here is a translation:
var ans2 = hotels.Select(h => new { h, hasVendor = h.vendorHotelId > 0 })
.GroupBy(hv => hv.hasVendor ? hv.h.vendorHotelId : hv.h.HotelId, hv => hv.h)
.Select(hg => hg.OrderBy(h => h.Price).First())
.Select(hmin => new {
HotelId = hmin.HotelId,
Price = hmin.Price,
vendorId = hmin.vendorId
})
.ToList();
NB: Somewhere someone should write an article on the advantages of conditional GroupBy expressions for unusual groupings.
Tables :
Component ComponentRights
-------------- ----------------
ComponentId (PK) ComponentRightsID
ComponentName ComponentId (FK)
RoleId
Lets say MyRoleId =2;
Now, I want to get all the records from both the tables but based on one condition. If I get same record but with different RoleId, then it should take only one record where RoleId = MyRoleId. If no duplicates, then condition is skipped.
Example:
Record 1:
------------
ComponentId = 1,
ComponentName = 'SampleComponent'
RoleId = 1
Record 2 :
-----------
ComponentId = 1,
ComponentName = 'SampleComponent'
RoleId = 2
* So In this case I should get Record 2.
Here is my sample code:
var Components = (from components in MyDB.Component
join componentRights in MyDB.ComponentRights on components.ComponentId equals componentRights.ComponentId
into AllComponents
from allComponent in AllComponents.DefaultIfEmpty()
where !(components.IsDeleted)
select new ComponentRightsModel()
{
ComponentRightsId = (!allComponent.IsDeleted) ? (Guid?)allComponent.ComponentRightsId : null,
ComponentId = components.ComponentUID,
ComponentName = components.ComponentName,
RoleId = allComponent.RoleId
}).ToList();
I'd suggest decomposing the problem into separate statements...
var Components = (from components in MyDB.Component
join componentRights in MyDB.ComponentRights on components.ComponentId equals componentRights.ComponentId
into AllComponents
from allComponent in AllComponents.DefaultIfEmpty()
where !(components.IsDeleted)
select new ComponentRightsModel()
{
ComponentRightsId = (!allComponent.IsDeleted) ? (Guid?)allComponent.ComponentRightsId : null,
ComponentId = components.ComponentUID,
ComponentName = components.ComponentName,
RoleId = allComponent.RoleId
});
var uniqueComponetIds = Components.GroupBy(x=>x.ComponentId).Select(x=> new {ComponentId = x.Key, Count = x.Count(y=>y.RoleId)}).Where(x=>x.Count == 1).Select(x=>x.ComponentId);
var filteredDuplicates = Components.Where(x=> !uniqueComponetIds.Contains(x.ComponentId) && x.RoleId == MyRoleId);
var finalComponents = Components.Where(x=> uniqueComponetIds.Contains(x.ComponentId).Concat(filteredDuplicates);
Note that this query would also filter out records where the component is duplicated but where the duplicated collected doesn't happen to have a role with RoleId == MyRoleId. If you want to include these as well, you can add a third statement to capture these as well.
I have a Customer Table that has a CustIndex column. From the UI a User can delete a customer that was for example at Index 3. What I need to do then determine if there was a Customer with an Index at 4 and renumber it to be 3, (so basically keep the sequence).
At the minute I just have some code like below:
private void UpdateCustomerIndexes(IList<CustomerDTO> customers)
{
var customerIndexes = customers.Select(c => new { c.customerId, c.customerIndex });
//unitIndexes.Select(u => u.)
}
I am keeping wanting to keep the CustomerId so if I need to update the DB I can say update customer set index = 3 where customerid = 4 for example.
So if I had 5 customer on the UI and I delete Customer at Index 5
If I set a breakpoint on customerIndexes, the data is:
{ CustomerId = 33, CustomerIndex = 1 },
{ CustomerId = 34, CustomerIndex = 2 },
{ CustomerId = 35, CustomerIndex = 3 },
{ CustomerId = 36, CustomerIndex = 4 }
So, in this case, the CustomerIndex is in sequence so there is nothing to do. However, lets say now I deleted CustomerIndex 2 on the UI. The data would now look like:
{ CustomerId = 33, CustomerIndex = 1 },
{ CustomerId = 35, CustomerIndex = 3 },
{ CustomerId = 36, CustomerIndex = 4 }
Now the Customer Index is out of sequence and I need to renumber CustomerIndex 3 to 2 and CustomerIndex 4 to 3 and then save this to the DB so I can say make the update statements setting the Index to the new value for that CustomerId.
I know my CustomerIndex will never go above 50 so would it be an idea to use something like:
var list = new List<int>(new[] { customerIndexes.Select(c => c.customerIndex) });
var result = Enumerable.Range(0, 50).Except(list);
However, I think this will only tell me if a number in sequence is missing - I am missing how to save which index needs to be updated for which customerid or do nothing in the case when they are in sequence
After you delete the record with CustomerIndex of 2, run the following SQL:
UPDATE TableName SET CustomerIndex = CustomerIndex - 1 WHERE CustomerIndex > 2
This will ensure the CustomerIndex of all 'greater' records are reduced by 1 to compensate.
Similarly, if a customer deletes CustomerIndex of 5, change both references to 2 above to 5.
Say we got a Database design like this.
Customer
Id Name
1 John
2 Jack
Order
Id CustomerId
1 1
2 1
3 2
OrderLine
Id OrderId ProductId Quantity
1 1 1 10
2 1 2 20
3 2 1 30
4 3 1 10
How would I create an entity framework query to calculate the total Quantity a given Customer has ordered of a given Product?
Input => CustomerId = 1 & ProductId = 1
Output => 40
This is what I got so far, through its not complete and still missing the Sum.
var db = new ShopTestEntities();
var orders = db.Orders;
var details = db.OrderDetails;
var query = orders.GroupJoin(details,
order => order.CustomerId,
detail => detail.ProductId,
(order, orderGroup) => new
{
CustomerID = order.CustomerId,
OrderCount = orderGroup.Count()
});
I find it's easier to use the special Linq syntax as opposed to the extension method style when I'm doing joins and groupings, so I hope you don't mind if I write it in that style.
This is the first approach that comes to mind for me:
int customerId = 1;
int productId = 1;
var query = from orderLine in db.OrderLines
join order in db.Orders on orderLine.OrderId equals order.Id
where order.CustomerId == customerId && orderLine.ProductId == productId
group orderLine by new { order.CustomerId, orderLine.ProductId } into grouped
select grouped.Sum(g => g.Quantity);
// The result will be null if there are no entries for the given product/customer.
int? quantitySum = query.SingleOrDefault();
I can't check what kind of SQL this will generate at the moment, but I think it should be something pretty reasonable. I did check that it gave the right result when using Linq To Objects.
intHi,
Pretty new to LINQ.
I have a Ratings table.
A User adds a set of Ratings for an Entity
There can be more than one Rating set for an Entity per User.
For example, let's say the Entity is a car. The car is rated on Appearance and Performance. And a User can rate the given car's appearance and performance more than once. So my table looks something like this (the Rating field is not an Identity column; it is an int on a scale of 1 - 10):
ReviewID UserID EntityID CatID Rating Body DateSubmitted
1 3 6 1 7 "drives great" 8/01/2010 02:36:28 PM
2 3 6 2 8 "looks great" 8/01/2010 02:36:28 PM
3 3 6 1 2 "broke down" 8/18/2010 11:39:58 PM
4 3 6 2 1 "paint flaked off" 8/18/2010 11:39:58 PM
Now, I have a helper method where I supply the UserID and the EntityID and I want to return the most recent set of Ratings (into a ViewModel that includes the Rating Category).
public static IQueryable<RatingViewModel> GetRatingViewModel(int EntityID, int UserID)
{
DB _db = new DB();
var a =
from rating in _db.Ratings
join ratingCat in _db.RatingCategories
on rating.RatingCategoryID equals ratingCat.RatingCategoryID
where rating.UserID == UserID
&& rating.EntityID == EntityID
select new RatingViewModel
{
Rater = rating.User,
RaterRating = rating,
RatingCategory = ratingCat
};
return a;
}
What kind of "where" or "group by" or "order by" do I need to add to ONLY grab the most recent set of Ratings for the given UserID and EntityID?
Thanks!
Consider ordering by the DateSubmitted on the return of the method, and then taking the number of entries that you'd like.
var a = from rating in _db.Ratings
join ratingCat in _db.RatingCategories
on rating.RatingCategoryID equals ratingCat.RatingCategoryID
where rating.UserID == UserID
&& rating.EntityID == EntityID
orderby rating.DateSubmitted descending
select new RatingViewModel
{
Rater = rating.User,
RaterRating = rating,
RatingCategory = ratingCat
}
.Take(10);
.OrderByDescending(a => a.DateSubmitted).FirstOrDefault()