Linq every occurrence of value, bind to ViewModel - c#

I need to get a list of players and every team that said player is associated to and add it to my ViewModel.
ViewModel
public class PlayersViewModel
{
public long PlayerID { get; set; }
public string PlayerName { get; set; }
public List<long> TeamID { get; set; } //Players can be assigned to 1 or more teams
}
I have a few different datatables going on:
PlayersInTeams (linking table)
+------------+---------+
| PlayerID | TeamID |
+------------+---------+
| 1 | 10001 |
| 1 | 10002 |
| 2 | 10002 |
| 3 | 10001 |
+------------+---------+
Players
+------------+---------+-----------+
| PlayerID | ForeName| Surname |
+------------+---------+-----------+
| 1 | John | Doe |
| 2 | Pete | Noe |
| 3 | Evan | Soe |
+------------+---------+-----------+
So for the above example tables, Player 1 - John Doe should have an array of 2 teamIDs in the ViewModel [10001, 10002].
Aim
I'm trying to have a List<PlayersViewModel> with a collection of TeamIDs.
Code
public List<PlayersViewModel> GetPlayers()
{
var playersInTeam = new PlayersInTeamsBLL();
var pit = playersInTeam.GetPlayersInTeams();
var playerDetail = Players;
var list = from p in pit
join team in Teams on p.TeamID equals team.TeamID // Only get teams that related to club
join pd in playerDetail on p.PlayerID equals pd.PlayerID //Link a player to
where pd.IsArchived == false
select new PlayersViewModel { TeamID = team.TeamID, PlayerID = p.PlayerID, PlayerName = pd.Forename + " " + pd.Surname};
return list.ToList();
}
I'm getting null PlayerIDs and obviously my TeamID isn't getting populated.
Any suggestions / solutions?

Try something like this:
var viewModels = playerDetail.Select(p => new PlayersViewModel()
{
PlayerID = p.PlayerID,
PlayerName = String.Format("{0} {1}", p.ForeName, p.Surname),
TeamID = pid.Where(pidElement => pidElement.PlayerID == p.PlayerID)
.Select(pidElement => pidElement.TeamID).ToList()
}).ToList();
In general it seems to me you're trying to tackle the problem from the wrong end. You want a list of players first, and then their teams second, not a list of player-team associations first, and player details second, so you should start with the playerDetail object (I assume it's an IEnumerable of all Player objects).
On a side note: consider that you can add a getter to your Player class which would give you the full name without the need to always concatenate the name and surname. Something like:
public string FullName
{
get { return String.Format("{0} {1}", this.FirstName, this.Surname); }
}

var results = yourContext.Players
.Select(p => new PlayersViewModel
{
PlayerID = p.PlayerID,
PlayerName = p.PlayerName,
TeamID = context.PlayersInTeams.Where(x => x.PlayerID == p.PlayerID)
}).ToList();

You need group them using group by like this:
var teamsFinal = from p in pit
join pd in playerDetail on p.PlayerID equals pd.PlayerID
where pd.IsArchived == false
group new {p,pd} by new
{
pd.PlayerID ,
pd.ForeName,
pd.SurName
} into g
select new PlayersViewModel
{
TeamID = g.Select(x => x.p.TeamID).ToList(),
PlayerID = g.Key.PlayerID,
PlayerName = g.Key.ForeName + " " + g.Key.SurName
};
Check this working Fiddle example

Related

Linq to sql query check for equality of tuples

How write linq to sql query to retrieve records from table below that (B ,C) be in list c.
Table is in database.
var c = new List<(int,int)>{(1,4), (3,6)};
+---+---+---+
| A | B | C |
+---+---+---+
| a | 1 | 4 |
| b | 2 | 5 |
| c | 3 | 6 |
+---+---+---+
Query should return a and c.
If you are talking about tuples being "fully"(all elements are sequentially equal) equal then you can just use contains:
var c = new List<(int,int)>{(1,3), (3,6)};
var table = new List<(int,int)>{(1,3), (2,5), (3,6)};
var res = table
.Where(i => c.Contains(i))
.ToList();
Equality and tuples
If #Caius Jard's assumption is right then just change .Where(i => c.Contains(i)) to .Where(i => !c.Contains(i))
I am not sure how your logic is but i think you are trying to do something like this,
Let's assume your table model looks like below,
public class MyTable {
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
public MyTable(string a, string b, string c) {
A = a;
B = b;
C = c;
}
}
And let's fill the data you have shared and query,
var c = new List<(int, int)> { (1, 4), (3, 6) };
List<MyTable> myTables = new List<MyTable>();
myTables.Add(new MyTable("a", "1", "4"));
myTables.Add(new MyTable("b", "2", "5"));
myTables.Add(new MyTable("c", "3", "6"));
var res = myTables.Where(x => c.Any(y => y.Item1.ToString() == x.B && y.Item2.ToString() == x.C)).Select(x => x.A);
Console.WriteLine(string.Join(" ", res));
Console.ReadKey();
This will print:
a c

I need to query table for values in two duplicate columns

I'm working in ASP.NET Core. I have a problem with querying rows which have same User_id and Definition_id, if there are any like that, I need ID of the row.
+----+---------+---------------+
| Id | User-id | Definition-id |
+----+---------+---------------+
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 2 | 2 |
| 4 | 3 | 1 |
| 5 | 4 | 1 |
| 6 | 4 | 1 |
| 7 | 5 | 2 |
| 8 | 6 | 1 |
+----+---------+---------------+
I need to query table like this, to return { 5, 6 } to me, because of them having same user AND definition ids.
I've tried Groupby for both values, but I can't get the IQueryable or IGrouping to give me the id of specific row.
I'd imagine it to work like that, but it ain't.
var placementsWithDuplicates =
from p in _context.Placements
group p by new { p.User_id, p.Definition_id } into what
select new
{
Id = what.Id,
User = what.User_id,
Defi = what.Definition_id,
};
foreach (var p in placementsWithDuplicates)
{
issues.Add(new IssueModel()
{
Type = "Praxe ID[" + p.Id + "]",
Name = "User id [" + p.User + "], Definition id [" + p.Defi + "]",
Detail = "So user shouldnt have data for more definitons!"
});
};
Thanks to Satish Hirpara for best answer, it needed a little update so I post the thing that ended up working well:
var B = from p in _context.Placements
group p by new { p.User_id, p.Definition_id } into what
where what.Count() > 1
select new
{
User_id = what.Key.User_id,
Definition_id = what.Key.Definition_id
};
var placementsWithDuplicates = from A in _context.Placements
join b in B on new { A.User_id, A.Definition_id } equals new { b.User_id, b.Definition_id }
select A;
Please find below SQL query:
SELECT A.*
FROM Placements A
INNER JOIN
(SELECT User_id, Definition_id FROM Placements
GROUP BY User_Id, Definition_id
HAVING COUNT(*) > 1) B
ON A.User_id = B.User_id AND A.Defination_id =
B.Defination_id
You can create a temp table to avoid join of sub query.
If you want linq query then I tried to create it from above query, please find it below:
--- sub query
var B = from p in Placements
group p by new { p.User_id, p.Definition_id } into what
where what.count() > 1
select new
{ User_id = what.User_id,
Definition_id =what.Definition_id
};
--- join
Var result = from A in Placements
Join B ON A.User_id = B.User_id
AND A.Defination_id = B.Defination_id
Select A
Please try this one.
Try This
var placementsWithDuplicates = from p in _context.Placements.Where(m => m.User_id == m.Definition_id)
select new {
Id = p.Id,
User = p.User_id,
Defi = p.Definition_id,
};
// this is same as the top one
var placementsWithDuplicates = from p in _context.Placements where p.User_id == p.Definition_id
select new {
Id = p.Id,
User = p.User_id,
Defi = p.Definition_id,
};
foreach (var p in placementsWithDuplicates)
{
issues.Add(new IssueModel()
{
Type = "Praxe ID[" + p.Id + "]",
Name = "User id [" + p.User + "], Definition id [" + p.Defi + "]",
Detail = "So user shouldnt have data for more definitons!"
});
};

How group List by key and transform the result

I have the following list and I need to transform it to get this result
original list
+----+--------------------+
| key| email |
+====+====================+
| 1 | one#gmail.com |
| 2 | two#gmail.com |
| 1 | three#gmail.com |
| 1 | four#gmail.com |
| 2 | five#gmail.com |
| 2 | six#gmail.com |
+----+----------------+-----
New list the mails concatenated with ;
+----+---------------------------------------------------+
| key| email |
+====+===================================================+
| 1 | one#gmail.com;three#gmail.com;four#gmail.com |
| 2 | two#gmail.com;five#gmail.com;six#gmail.com |
+----+---------------------------------------------------+
How can i accomplish this task with c# Linq? thanks
Try in this way:
x.GroupBy(t => new {t.Id})
.Select(t => new {
Id = t.Key.Id,
email = String.Join(", ", t.Select(p => p.Email).ToArray())
}
Supposing that you have a class similar to this:
public class myEmails
{
public int Key { get; set; }
public string Email { get; set; }
}
and a List<myEmails> that could be like this:
List<myEmails> emails = new List<myEmails>();
You could GroupBy the Key value and then Join all strings (Emails) related to that Key, creating a new Dictionary<int, string> that contains all the Emails grouped by the given Key:
var emailsDictionary = emails
.GroupBy(eml => eml.Key)
.ToDictionary(grp => grp.Key, grp => string.Join(" ", grp.Select(eml => eml.Email)));
Test the result with:
emailsDictionary.ToList().ForEach(dict => Console.WriteLine($"{dict.Key}: {dict.Value}"));
It should give you:
1: one#gmail.com three#gmail.com four#gmail.com
2: two#gmail.com five#gmail.com six#gmail.com
As a note, if you're interested, you could also use Aggregate instead of Join, so this:
grp => string.Join(" ", grp.Select(eml => eml.Email))
could also be expressed as:
grp => grp.Aggregate("", (s, eml) => (eml.Email + " " + s))

Linq Union does not work

I have a two lists rca and purchase as follow.
List<GroupDate> rca = (from sold in GetSoldOut
group sold by new { sold.CreatedDate, sold.SubCategoryID }
into g
select new GroupDate
{
Date = g.Key.CreatedDate,
SubCategoryID = g.Key.SubCategoryID,
Count = g.Count()
}).ToList();
and
List<GroupDate> purchase = (from sold in stock
group sold by new { sold.CreatedDate, sold.SubCategoryID }
into g
select new GroupDate
{
Date = g.Key.CreatedDate,
SubCategoryID = g.Key.SubCategoryID,
Count = g.Sum(a => a.Quantity)
}).ToList();
And Join this two lists as follow.
var leftOuterJoinRP = from first in replace
join last in prepaid
on new { first.Date, first.SubCategoryID } equals new { last.Date, last.SubCategoryID }
into temp
from last in temp.DefaultIfEmpty(new GroupDate { })
select new CardBalance
{
Date = first.Date,
SubCategoryID = first.SubCategoryID,
ReDemage = first.Count,
Prepaid = last.Count
};
var rightOuterJoinRP = from last in prepaid
join first in replace
on new { last.Date, last.SubCategoryID } equals new { first.Date, first.SubCategoryID }
into temp
from first in temp.DefaultIfEmpty(new GroupDate { })
select new CardBalance
{
Date = last.Date,
SubCategoryID = last.SubCategoryID,
ReDemage = first.Count,
Prepaid = last.Count
};
leftOuterJoinRP contains
Date---| Balance | OpeningStock | Prepaid | Purchase | RCA | Demage | SubCategoryId
1/1/17 | 0-------| 0----------- | 1------ | 600 -----| 2-- | 0 ---- | 84
and
rightOuterJoinRP contains
Date---| Balance | OpeningStock | Prepaid | Purchase | RCA | Demage | SubCategoryId
1/1/17 | 0-------| 0----------- | 1------ | 600-----| 2-- | 0 ---- | 84
1/2/17 | 0-------| 0----------- | 1------ | 110-----| 1-- | 0 ---- | 84
Union leftOuterJoinRP and rightOuterJoinRP as follow.
var fullOuterJoinRP = leftOuterJoinRP.Union(rightOuterJoinRP);
But it does not union. fullOuterJoinRP get all rows.
You need to use the Union method which takes an IEqualityComparer<T> parameter.
Let's say you have a TestClass
public class TestClass
{
public int TestInteger { get; set; }
public string TestString { get; set; }
}
And create two lists
List<TestClass> list1 = new List<TestClass>();
list1.Add(new TestClass() { TestInteger = 1, TestString = "t1" });
list1.Add(new TestClass() { TestInteger = 2, TestString = "t2" });
List<TestClass> list2 = new List<TestClass>();
list2.Add(new TestClass() { TestInteger = 1, TestString = "t1" });
list2.Add(new TestClass() { TestInteger = 3, TestString = "t3" });
IEnumerable<TestClass> list3 = list1.Union(list2);
Here, the Union method will return all four objects, like in your question.
The Union method needs an IEqualityComparer<TestClass> parameter to compare the objects.
public class TestClassComparer : IEqualityComparer<TestClass>
{
public bool Equals(TestClass x, TestClass y)
{
//Check whether the objects are the same object.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether the class properties are equal.
return x != null && y != null && x.TestInteger.Equals(y.TestInteger) && x.TestString.Equals(y.TestString);
}
public int GetHashCode(TestClass obj)
{
//Get hash code for the TestString field if it is not null.
int hashTestString = obj.TestString == null ? 0 : obj.TestString.GetHashCode();
//Get hash code for the TestInteger field.
int hashTestInteger = obj.TestInteger.GetHashCode();
//Calculate the hash code for the TestClass object.
return hashTestString ^ hashTestInteger;
}
}
Now, if you call
IEnumerable<TestClass> list3 = list1.Union(list2, new TestClassComparer());
The resulting list3 will have three unique objects.

Filter records from Datatable on the basis of list

I have a class:
public class Cards
{
private string _type= string.Empty;
private string _name= string.Empty;
public string Type
{
get { return _type; }
set { _type= value; }
}
public string Name
{
get { return _name; }
set { _name= value; }
}
}
I have an object of this class.
public List<Cards> CardTypes = new List<Cards>();
Values in list Cards is:
Name Type
==============
Visa Vi
Master MA
Discover DI
I have a DataTable cardTable with following columns:
Name,Value,CCvName
+---+------------+-------------+
|Val| Name | CCV |
+---+------------+-------------+
| 1 | Visa | 441 |
| 2 | Master | 121 |
| 3 | Amex | 111 |
| 4 | Diners | 222 |
+---+------------+-------------+
Both List and DataTable have unique values. I want to filter the data from datatable on the basis of Name field in List (delete other records from cardTable). All the values are of string type.
The resulting cardTable should be:
+---+------------+-------------+
|Val| Name | CCV |
+---+------------+-------------+
| 1 | Visa | 441 |
| 2 | Master | 121 |
+---+------------+-------------+
Thanks in advance.
An easy way is to use RowFilter (either on a new DataView or the default DataView of the DataTable).
Given cardTable and cardTypes:
var view = new DataView(cardTable)
{
// create filter: [Name] IN ('Visa','Master','Discover')
RowFilter = String.Format("[Name] IN ({0})", String.Join(",", cardTypes.Select(t => "'" + t.Name + "'")))
};
view now contains the rows you're looking for.
If you really want a LINQ solution, you could use a simple Join:
cardTable = cardTable.AsEnumerable()
.Join(cardTypes,
i => i.Field<string>("Name"),
o => o.Name,
(i, o) => i)
.CopyToDataTable();
You can write LINQ join query returning rows without corresponding card type in list:
var rowsToDelete = from r in cardTable.AsEnumerable()
join c in CardTypes
on r.Field<string>("Name") equals c.Name into g
where !g.Any()
select r;
And then just remove those rows:
foreach(var row in rowsToDelete)
cardTable.Rows.Remove(row);

Categories

Resources