Linq GroupBy throws ArgumentOutOfRangeException - c#

I have these two tables
Animals Activities
+----+-------+ +----+------------+----------+------------+
| Id | Name | | Id | Activity | FkAnimal | Date |
+----+-------+ +----+------------+----------+------------+
| 1 | Cats | | 1 | Ball | 2 | 2015-05-21 |
+----+-------+ +----+------------+----------+------------+
| 2 | Dogs | | 2 | Pet | 2 | 2015-06-07 |
+----+-------+ +----+------------+----------+------------+
| 3 | Birds | | 3 | Running | 1 | 2014-11-03 |
+----+-------+ +----+------------+----------+------------+
| 4 | Kill a fly | 1 | 2014-08-05 |
+----+------------+----------+------------+
| 5 | Kill a fly | 3 | 2014-08-05 |
+----+------------+----------+------------+
What I want is the result of this query
SELECT Animals.Name, Animals.Id, Activities.Data
FROM Activities
INNER JOIN Animals ON Animals.Id = Activities.Id
GROUP BY Animals.Name, Animals.Data
In LINQ from the Entity Framework
Here's my attempt:
//My repository is of type IRepository<Activities>
var list = Repository.GetAll().GroupBy(a => a.Animals).Select((grouping,i) => new {
name = grouping.Key.Name,
id = grouping.Key.Id,
data = grouping.ElementAt(i).Data
}).ToList();
Unfortunately the ToList() method generate ArgumentOutOfRangeException, and if I debug the lambda it shows that i goes out of range

The i in .Select((grouping,i) => is the index of the group. In your example, .GroupBy(a => a.Animals) will return an IGrouping which is, essentially, just an IEnumerable with a Key property. The result from .GroupBy(a => a.Animals) will, loosely, look something like this (not sure exactly what your DbContext looks like):
{[
{
Key: Dogs
GetEnumerator(): [
{
Id: 1
Activity: Ball
Date: 2015-05-21
},
{
Id: 2
Activity: Pet
Date: 2015-06-07
}
]
},
{
Key: Cats
GetEnumerator(): [
{
Id: 3
Activity: Running
Date: 2014-11-03
},
{
Id: 4
Activity: Kill a fly
Date: 2014-08-05
}
]
},
{
Key: Birds
GetEnumerator(): [
{
Id: 5
Activity: Kill a fly
Date: 2014-08-05
}
]
}
]}
The Select method is iterating over the groups, not the elements in the group. So the i in .Select((grouping,i) =>, in this case, refers to the index of the group (there are three groups) not an element in a group. Within your select you are calling data = grouping.ElementAt(i).Data, grouping in this case is an IGropuing which is an IEnumerable so ElementAt(i) is asking for the ith element in whichever group is currently being evaluated. By the time you get the third group i will be 2 but there is only one element in the group, hence the exception; at least in this example, your groups may come back in a different order but the principle is the same.
You probably want something like this:
var list =
Repository
.GetAll()
.GroupBy(a => a.Animals)
.Select(grouping => new {
name = grouping.Key.Name,
id = grouping.Key.Id,
data = grouping.Select(x => x)
}).ToList();

does this work...
var res= from act in Repository.GetAll()
let anm=act.Animals.Single(a=>a.Id=act.FkAnimal)
select new {
anm.Id, anm.Name, act.Activity
};

Related

Getting Multiple Lists and displaying them to the View

I have a system where I enter in other, employee, and dealer information as such (there is more fields but trying to keep it simple).
+----+---------+--------------+------------+-------+
| ID | itemId | memberTypeId | MemberType | price |
+----+---------+--------------+------------+-------+
| 1 | 202 | 2 | employee | 2.00 |
| 2 | 202 | 3 | dealer | 3.00 |
| 3 | 101 | 1 | other | 4.00 |
+----+---------+--------------+------------+-------+
I’m trying to make the Update functionality on my site. When I make a DB call based on the ItemId to get everything.
Here is such code from helper class:
public class Item {
public static List<ItemOption> GetItemOpttions(long itemID)
{
using (DBContext context = new DBContext())
{
List<ItemOptionDTO> ItemOptionsDto = (
from I in context.ItemOptions
where I.ItemID == itemID
select new ItemOptionDTO
{
ItemID = I.ItemID,
MemberTypeId = I.MemberTypeId
MemberType = I.MemberType,
Price = I.Price,
}).ToList();
return ItemOptionsDto;
}
}
}
So, when I get the data and store it in a list. It’s either one row of data or two rows based on how it was saved. The option “Other” will always be saved into the DB as one row of data as where “employee and dealer” will be saved as two separate row sharing the same ItemId. When called the number of rows will vary based on each item created at an earlier date/time.
I am trying to get this info back to the controller and send it to the View showing the correct values that might get updated. Here is what I have in the controller. I'm not sure if this is the correct way of doing this or if there is a better way.
Also to add that the if the item was saved as an employee and dealer it will leave the other list empty/null. I don't think I can do this because it will cause a null exception error
This is what I have so far in the controller:
public ActionResult UpdateItem(long itemID) {
List<ItemOptionDTO> itemOptionDto = Item.GetItemOpttions(itemID);
var other = itemOptionDto.Where(x => x.MemberTypeId == 1).FirstOrDefault();
var employee = itemOptionDto.Where(x => x.MemberTypeId == 2).FirstOrDefault();
var dealer = itemOptionDto.Where(x => x.MemberTypeId == 3).FirstOrDefault();
UpdateItemViewModel viewModel = new UpdateItemViewModel(itemID, employee, dealer, option)
{
ItemId = option.ItemId,
MemberType = option.MemberType,
Price = other.price
ItemId = employee.ItemId,
MemberType = employee.MemberType,
Price = employee.price
ItemId = dealer.ItemId,
MemberType = dealer.MemberType,
Price = dealer.price
};
return View(viewModel);
}
Let me know if there is anything else I can provide.

Loading child entities with parent object graph using Entity framework

I am trying to model something similar to a graph representation of a object where it's children are dependencies on which the parent depends.
Example here is the table structure.
Initative
Id | Name
1 | Init1
2 | Init2
3 | Init3
4 | Init4
InitiativeChildren
Id |InitiativeId InitiativeChildrenId
1 | 1 | 2
2 | 1 | 3
3 | 2 | 4
Categories
Id | InitiativeId | Name
1 | 1 | Init1Category1
2 | 1 | Init1Category2
3 | 1 | Init1Category3
4 | 2 | Init2Category1
5 | 2 | Init2Category2
6 | 2 | Init2Category3
7 | 3 | Init3Category1
8 | 3 | Init3Category2
Initiative Id = 1 depends on Initiative Id = 2, 3 where InitiativeId = 2 further depends on Initiative Id = 4
I want to write a query to pull a object like this for Initiative Id = 1
Initiative
{
Id : 1
Children = [ Initiative {
Id = 2,
Children = [ Initiative
{
Id = 4,
Children = []
}]
},
Initiative {
Id = 3,
Children = []
}]
}
i.e. I want the child initiative to be Initiative Objects which will again have child initiatives and so on.
I want the structure to be like this so that I can use depth first search to resolve the children objects before acting on that object.
The database structure I designed is
And the Entity framework query I have written is
var result = context.Initiatives
.Include(m => m.InitiativeChildrens)
.Include(m => m.Categories)
.Where(m => m.Id == 1)
.ToList();
What I get currently is that the the ChildrenInitiative has two children as it should but the Initiative to that child initiative is again the same Initiative with Id = 1 as opposed to a Initiative Object with ChildInitiative.ChildInitiativeId
Lets assume that this representation doesn't lead to modelling a cyclic graph for now

How to find the distinct values of a column and find the sum of those same values of another column?

In my c# WinForm application, I have a DataTable keeping track of sales of fruits and it's like:
/*TableA*/
Name | QuantitySold
Apple | 5
Orange | 10
Apple | 3
Grape | 2
Banana | 6
Orange | 7
Apple | 2
Grape | 2
Now I want to filter them by the same fruit names AND get the sums of each of those fruits sold at the same time, creating a new resultant DataTable, which should look like
/*TableB*/
Name | TotalSold
Apple | 10
Orange | 17
Grape | 4
Banana | 6
How could I achieve this?
I have found the count of distinct fruit names by
int distinctCt = TableA.AsEnumerable()
.Select(row=>row.Field<string>("Name"))
.Distinct().Count();
But I realized this won't go anywhere from here.
Can someone please give me an idea on how to do this?
Use GroupBy and Sum:
var nameGroups = TableA.AsEnumerable().GroupBy(r => r.Field<string>("Name"));
var TableB = TableA.Clone();
TableB.Columns["QuantitySold"].ColumnName = "TotalSold";
foreach(var g in nameGroups)
{
TableB.Rows.Add(g.Key, g.Sum(r => r.Field<int>("QuantitySold")));
}
You need to use GroupBy, try this:
var x = TableA.AsEnumerable()
.GroupBy(r=>r.Field<string>("Name"))
.Select(sm => new
{
Name = sm.First().Field<string>("Name"),
QuamtitySold = sm.Sum(q => q.Field<int>("QuantitySold"))
});

Linq expression checkin if one user is following another

I have a table that stores followers and followees.These are based on the guids they have.
before i want to make this relation i want to check and see if the person is already following the person
EDIT
bool userExist = _databaseEntities.Users.Count(e => e.UserName == followerName) > 0;
if(userExist)
{
var user1 = _databaseEntities.Users.FirstOrDefault(y => (y.UserName == username));
var user2 = _databaseEntities.Users.FirstOrDefault(z => (z.UserName == followerName));
So i get two users and check if they are there and then check if their userIds are in the table of followers forming a relationship.
so I have this _db.Followers.Count(c => (c.UserId == user1.UserId && c.FollowerId == user2.UserId) < 0 );
but it always comes out as 0 even if the relation is there
How can i do this right?
If i understand correctly, you have a table like this:
| UserId | FollowerId |
|----------|--------------|
| Homer | Marge |
| Homer | Lisa |
| Marge | Homer |
| Marge | Bart |
| Bart | |
| Lisa | Bart |
|----------|--------------|
And the related User class should contain at least a string property for the UserId and a Collection of Users (those who the user is following)
So you can have a method inside User like this:
public bool CanFollow(User followee)
{
return !Followee.Any(x => x.UserId == followee.UserId);
}
It's easier and more logical and you simply use it like that
User homer = _db.Followers.Where(x => x.UserId == "Homer").FirstOrDefault();
User marge = _db.Followers.Where(x => x.UserId == "Marge").FirstOrDefault();
// can Homer follow Marge?
homer.CanFollow(marge);

Search on all fields of an entity

I'm trying to implement an "omnibox"-type search over a customer database where a single query should attempt to match any properties of a customer.
Here's some sample data to illustrate what I'm trying to achieve:
FirstName | LastName | PhoneNumber | ZipCode | ...
--------------------------------------------------
Mary | Jane | 12345 | 98765 | ...
Jane | Fonda | 54321 | 66666 | ...
Billy | Kid | 23455 | 12345 | ...
If the query was "Jane", I'd expect row #1 to be returned as well as row #2.
A query for 12345 would yield rows #1 and #3.
Right now, my code looks pretty much like this:
IEnumerable<Customer> searchResult = context.Customer.Where(
c => c.FirstName == query ||
c.LastName == query ||
c.PhoneNumber == query ||
c.ZipCode == query
// and so forth. Fugly, huh?
);
This obviously works. It smells like really bad practice to me, though, since any change in the Entity (removal of properties, introduction of new properties) would break stuff.
So: is there some LINQ-foo that will search across all properties of whatever Entity I throw at it?
first find all properties within Customer class with same type as query:
var stringProperties = typeof(Customer).GetProperties().Where(prop =>
prop.PropertyType == query.GetType());
then find all customers from context that has at least one property with value equal to query:
context.Customer.Where(customer =>
stringProperties.Any(prop =>
prop.GetValue(customer, null) == query));

Categories