group by on dictionary with custome class key,value objects using linq - linq

I have a requirement where i have to do a group by on the dictionary and get the resulting rows on the basis of a group by into another dictionary having key,value pair , value being a List(Positions).
Here is the below code snippet which explains my problem statement:
public class Positions
{
public string Value1 { get; set; }
public int Value2 { get; set; }
public string Value3 { get; set; }
public string Value4 { get; set; }
public string Value5 { get; set; }
public string Value6 { get; set; }
public string Value7 { get; set; }
public string Value8 { get; set; }
public string Value9 { get; set; }
public string Value10 { get; set; }
public string Value11 { get; set; }
public string Value12 { get; set; }
}
public struct PositionKey
{
public string Value1 { get; set; }
public int Value2 { get; set; }
public string Value3 { get; set; }
public string Value4 { get; set; }
public string Value5 { get; set; }
public string Value6 { get; set; }
public override int GetHashCode()
{
return (Value1 != null ? Value1.GetHashCode() : 1)
^ (Value2 > 0 ? Value2.GetHashCode() : 1)
^ (Value3 != null ? Value3.GetHashCode() : 1)
^ (Value4 != null ? Value4.GetHashCode() : 1)
^ (Value5 != null ? Value5.GetHashCode() : 1)
^ (Value6 != null ? Value6.GetHashCode() : 1);
}
public override bool Equals(object obj)
{
PositionKey compositeKey = (PositionKey)obj;
return Value1 == compositeKey.Value1
&& Value2 == compositeKey.Value2
&& Value3 == compositeKey.Value3
&& Value4 == compositeKey.Value4
&& Value5 == compositeKey.Value5
&& Value6 == compositeKey.Value6;
}
}
public struct GroupbyPositionKey
{
public string Value1 { get; set; }
public int Value2 { get; set; }
public override int GetHashCode()
{
return (Value1 != null ? Value1.GetHashCode() : 1)
^ (Value2 > 0 ? Value2.GetHashCode() : 1);
}
public override bool Equals(object obj)
{
PositionKey compositeKey = (PositionKey)obj;
return Value1 == compositeKey.Value1
&& Value2 == compositeKey.Value2;
}
}
public class program
{
/*
Value1 Value2 Value3 Value4 Value5 Value6 Value7 Value8 Value9 Value10 Value11 Value12
-------------------------------------------------------------------------------------------------
v1 1 val1 val2 val3 val4 val5 val6 val7 val8 val9 val10
v1 1 val2 val3 val4 val5 val6 val7 val8 val9 val10 val11
v3 4 val3 val4 val5 val6 val7 val8 val9 val10 val11 val12
v3 4 val4 val5 val6 val7 val8 val9 val10 val11 val12 val13
v3 5 val5 val6 val7 val8 val9 val10 val11 val12 val13 val14
v4 6 val6 val7 val8 val9 val10 val11 val12 val13 val14 val15
v4 6 val7 val8 val9 val10 val11 val12 val13 val14 val15 val16
v4 7 val8 val9 val10 val11 val12 val13 val14 val15 val16 val17
v4 7 val9 val10 val11 val12 val13 val14 val15 val16 val17 val18
Group by - Value1 Value2 Value3 Value4 Value5 Value6 Value7 Value8 Value9 Value10 Value11 Value12
Get List of the rows after the grouping on the basis of group by Value1,Value2
*/
public static void main()
{
Dictionary<PositionKey, Positions> dictPositons = new Dictionary<PositionKey, Positions>();
Positions obj = new Positions();
obj.Value1 = "v1";
obj.Value2 = 1;
obj.Value3 = "val1";
obj.Value4 = "val2";
obj.Value5 = "val3";
obj.Value6 = "val4";
obj.Value7 = "val5";
// ........ and so on.. and so forth...for all the objects.
/*
I have a datatable as above and i am inserting the rows in the collection object of class <Positions> with respective key
and add the same to the dictionary.
*/
PositionKey key = new PositionKey();
key.Value1 = "v1";
key.Value2 = 1;
key.Value3 = "val3";
key.Value4 = "val4";
key.Value5 = "val5";
key.Value6 = "val6";
if (!dictPositons.ContainsKey(key))
{
dictPositons.Add(key, obj); // this dictionary would have the raw data which would have all the rows from the table as a dictionary collection
}
/*
Now I have to create another dictionary which gives me a list of all the records by grouping on the basis
of the key <GroupbyPositionKey> which is nothing but <Value1,Value2>
The resulting dictionary should look like Dictionary<GroupbyPositionKey,List<Positions>>
*/
Dictionary<GroupbyPositionKey, List<Positions>> result = new Dictionary<GroupbyPositionKey, List<Positions>>();
result = dictPositions.GroupBy(....); // not sure how ?
}
}
In the result i would want to have another dictionary with the key object with value1,value2 and value object as List(Positions). I am not sure how to approach the group by in the dictionary to get the desired result.
I have already achieved this result by looping through the dictionary manually and then pick and insert into the other dictionary on the basis of new key. But i wanted to know if there is a LINQ way of doing this which is going to be much shorter.

Within your GroupBy statement, you will need to create a new GroupbyPositionKey class and then use the ToDictionary method to select your key and the list
Dictionary<GroupbyPositionKey, List<Positions>> result = dictPositons
.GroupBy(x => new GroupbyPositionKey { Value1 = x.Key.Value1, Value2 = x.Key.Value2 })
.ToDictionary(x => x.Key, x => x.Select(y => y.Value).ToList());

Related

LINQ from a list inside a class

I have the following Model class:
public partial class EmployeeInfo
{
public int EmployeeInfoId { get; set; }
public string FirstName { get; set; } = null!;
public int? JobTitleLookupId { get; set; }
public virtual JobTitleLookup? JobTitleLookup { get; set; }
}
public partial class JobTitleLookup
{
public int JobTitleLookupId { get; set; }
public string Title { get; set; } = null!;
public virtual ICollection<EmployeeInfo> EmployeeInfos { get; } = new List<EmployeeInfo>();
}
I have JobTitleLookupId in my employeeeInfo database table. How can i get the name of the jobtitle if i have the corresponding ID in employeeInfo Table.
below is my JobTitleLookup table:
JobTitleLookupID title
1 title1
2 title2
3 title3
EmployeeInfo table
EmployeeInfoId FirstName JobTitleLookupID
1 test1 2
2 test3 1
3 testx 3
How can I get the job title if I have the employeeinfoId and jobTitleLookupID using LINQ.'
this is what I tried so far:
public async Task<List<string?> GetJobTitle(string employeeId)
{
var query = _ackContext.EmployeeInfos
.Include(c => c.JobTitleLookup)
.Where(c => c.EmployeeNumber == employeeId)
}
this is something I wrote in sql. I want the same in LINQ
SELECT
title
FROM
employeeInfo e
INNER JOIN JobTitleLookup j ON
e.JobTitleLookupID =j.JobTitleLookupID
AND
EmployeeInfoID = 212;
To select something precise, you have to use Select.
public Task<List<string?> GetJobTitle(string employeeId)
{
return _ackContext.EmployeeInfos
.Where(c => c.EmployeeNumber == employeeId)
.Select(c => c.JobTitleLookup.Title)
.ToListAsync();
}

Building a list using LINQ from two lists

I have two lists:
List1 = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K' }
List2 = { 'B', 'C', 'D' }
List1 is all the columns in a table and List2 are the columns that make up a foreign or primary key on that same table.
In this example, 'A', 'B', 'C' and 'D' are a primary key of a table. 'B', 'C' and 'D' are a foreign key of the same table. 'G' and 'H' are two columns of a table I don't want to include.
I can't seem to be able to write a LINQ statement that produces this:
List3 = { 'B', 'C', 'D', 'E', 'F', 'I', 'J', 'K' }
List3 is a list of the parameters I want to give to an "UPDATE" stored procedure I am generating. List2 + 'K' will be my "WHERE"; 'E', 'F', 'I' and 'J' will be the columns the procedure will use in the "SET".
Both List1 and List2 will be different every time the LINQ is executed.
All lists are of type List where DbColumn is defined as:
public class DbColumn
{
public string Name { get; set; }
//public bool IsPrimaryKey { get; set; }
//public bool IsForeignKey { get; set; }
public int OrdinalPosition { get; set; }
public string DataType { get; set; }
public int CharMaxLength { get; set; }
public bool AllowNulls { get; set; }
public static DbColumn Create(string name, int ordinal_position, string data_type, int charMaxLength, string is_nullable)
{
DbColumn column = new DbColumn();
column.Name = name;
//column.IsPrimaryKey = isPk;
//column.IsForeignKey = isFk;
column.OrdinalPosition = ordinal_position;
column.DataType = data_type;
column.CharMaxLength = charMaxLength;
if (!String.IsNullOrEmpty(is_nullable))
column.AllowNulls = is_nullable.ToUpper() == "YES" ? true : false;
else
column.AllowNulls = false;
return column;
}
public override string ToString()
{
return Name;
}
}
Columns can be part of DbConstraint and DbTable. DbTable also has DbConstraint as a properties:
public class DbTable
{
public string Name { get; set; }
public string Catalog { get; set; }
public string Schema { get; set; }
public List<DbColumn> Columns { get; set; }
public DbSProc Insert { get; set; }
public DbSProc Update { get; set; }
public DbSProc Delete { get; set; }
public List<DbSProc> ReadProcedures { get; set; }
public List<DbConstraint> Constraints { get; set; }
public static DbTable Create(string name, string catalog, string schema, List<DbColumn> columns)
{
DbTable table = new DbTable();
table.Catalog = catalog;
table.Schema = schema;
table.Name = name;
table.Columns = columns;
table.ReadProcedures = new List<DbSProc>();
return table;
}
public override string ToString()
{
return Name;
}
}
public class DbConstraint
{
public string Name { get; set; }
public bool IsPrimary { get; set; }
public List<DbColumn> Columns { get; set; }
public static DbConstraint Create(string name, bool isPrimary)
{
DbConstraint constraint = new DbConstraint();
constraint.Name = name;
constraint.IsPrimary = isPrimary;
constraint.Columns = new List<DbColumn>();
return constraint;
}
public override string ToString()
{
return Name;
}
}
The goal of the LINQ statement is to select for parameters only those columns that are necessary for the "WHERE" piece (e.g.: a foreign/primary key plus "_VerCol") and those necessary for the "SET" piece (non-primary keys).
You can find the code on CodePlex: https://sqlmeth.codeplex.com.
Can anybody help me please?
Thank you!
I assume you know the characters you want to exclude.
List<char> a = new List<char>() { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K' };
List<char> b = new List<char>() { 'B', 'C', 'D' };
List<char> exclusionList = new List<char> {'A','G', 'H'};
List<char> c = a.Select(x => x).Where(x => !exclusionList.Contains(x)).ToList();

Get the Value of enum from the class

public class EmpModel
{
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public Gender Gender { get; set; }
public int DepartmentId { get; set; }
}
#region [ Enumeration]
public enum Gender
{
Male = 0,
FeMale = 1
}
Now how to get enum value
var employees = root.Elements("Employee");
foreach (var element in employees)
{
var employee = new EmpModel
{
UserName = element.Element("UserName").Value,
FirstName = element.Element("FirstName").Value,
LastName=element.Element("LastName").Value,
Age=Convert.ToInt32( element.Element("Age").Value),
Gender= element.Element("Gender").Value, // On this line shows error
DepartmentId=Convert.ToInt32(element.Element("Department").Value)
};
Thanks
Enumerations in C# are represented by integers (Int32) internally by default. So in this case, if your XML file contains the string "0" or "1", you can simply parse it and then cast it the the correct enum type:
Gender = (Gender) Int32.Parse(element.Element("Gender").Value);
If you are reading strings that correspond to the names of the Enumeration, you should use Enum.Parse():
Gender = (Gender) Enum.Parse(typeof(Gender), element.Element("Gender").Value);

Getting error: 'System.Collections.Generic.IEnumerable<AnonymousType#1>' does not contain a definition for 'ToList'

I am doing the below
List<A> lstA = new List<A>();
Enumerable.Range(1, 10).ToList().ForEach(i => lstA.Add(new A { Prop1 = i, Prop2 = "Prop2" + i.ToString() }));
List<B> lstB = new List<B>();
Enumerable.Range(1, 10).ToList().ForEach(i => lstB.Add(new B { Prop1 = i, Prop3 = DateTime.Now }));
var res = (from a in lstA
join b in lstB on a.Prop1 equals b.Prop1
select new
{
Prop1 = a.Prop1
,
Prop2 = a.Prop2
,
Prop3 = b.Prop3
}).ToList<C>();
Means the combined result want to store in List.
At that time getting the error
'System.Collections.Generic.IEnumerable<AnonymousType#1>' does not contain a definition for 'ToList' and the best extension method overload 'System.Linq.Enumerable.ToList<TSource>(System.Collections.Generic.IEnumerable<TSource>)' has some invalid arguments
How to do so?
class A
{
public int Prop1 { get; set; }
public string Prop2 { get; set; }
}
class B
{
public int Prop1 { get; set; }
public DateTime Prop3 { get; set; }
}
class C
{
public int Prop1 { get; set; }
public string Prop2 { get; set; }
public DateTime Prop3 { get; set; }
}
Thanks
You're creating a sequence of a new anonymous type, and trying to call ToList<C> on it. That won't work. The simple solution is to change your query to create a sequence of C:
var res = (from a in lstA
join b in lstB on a.Prop1 equals b.Prop1
// Note the "new C" part here, not just "new"
select new C
{
Prop1 = a.Prop1,
Prop2 = a.Prop2,
Prop3 = b.Prop3
}).ToList();
You cannot turn an anonymous type into a C.
You should create a C directly by writing new C { ... }.

Linq projection that flattens a list into a deliminated string

I am trying to concat and comma deliminated (or space) a list and project it. I have some sample code below.
public class Friend
{
public string Name { get; set; }
}
public class Person
{
public int PersonID { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
List<Friend> Friends { get; set; }
}
public class ProjectedPerson
{
public int PersonID { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
public string FriendsList { get; set; }
}
public class Test
{
public void MyTest()
{
var query = from p in MyDataStore.Person
select p;
var results = from q in query
select new ProjectedPerson
{
PersonID = q.PersonID,
FirstName = q.FirstName,
Surname = q.Surname,
FriendsList = q.FriendsList.Concat() //??? How can I concat this and return a string
};
}
}
Use string.Join (note that the list will need to be in memory first), to concatentate the selected properties from your Friend objects. If you are using .NET 3.5, you'll need to use ToArray() as well as the overloads on string.Join in 3.5 require an array.
var query = (from p in MyDataStore.Person
select p).ToList(); // <-- bring into memory with ToList()
var results = from q in query
select new ProjectedPerson
{
PersonID = q.PersonID,
FirstName = q.FirstName,
Surname = q.Surname,
FriendsList = string.Join( ", ", q.Friends.Select( f => f.Name ) )
};
string.Join is the better way but abusing LINQ is just so fun.
var query = (from p in MyDataStore.Person
select p).ToList(); // <-- bring into memory with ToList()
var results = from q in query
select new ProjectedPerson
{
PersonID = q.PersonID,
FirstName = q.FirstName,
Surname = q.Surname,
FriendsList = q.Friends.Aggregate<Friend, string>(null, (accum, f) => accum + (accum == null ? accum : ", ") + f.Name)
};

Resources