class Customer
{
public int ID { get; set; }
public string Name { get; set; }
}
class Order
{
public int ID { get; set; }
public string Product { get; set; }
}
var customers = new Customer[]
{
new Customer{ID = 5, Name = "Sam"},
new Customer{ID = 6, Name = "Dave"},
new Customer{ID = 7, Name = "Julia"},
new Customer{ID = 8, Name = "Sue"}
};
var orders = new Order[]
{
new Order{ID = 5, Product = "Book"},
new Order{ID = 6, Product = "Game"},
new Order{ID = 7, Product = "Computer"},
new Order{ID = 8, Product = "Shirt"}
};
IEnumerable<Object> query =
from c in customers
join o in orders on c.ID equals o.ID
select new { c.Name, o.Product };
IList<Object> AA = query.ToList<Object>();
This one return new object that is shown into picture
[But I want to access this object as customer and order how can I get data as 'customerObject.propertyName and order.propertyName" instead of getting array with string. Can I get list of data with two object like customer and order object so I can access those data using that object]
It returns aa[0] = {name=" sam ", product=" Book"} but I want something like aa[0] = {Customer.Name , Order.product }
[1]
You could try to return the mapped objects. Considering you have your mapped entities, try something like this:
var result = (from c in customers
join o in orders on c.ID equals o.ID
select new{ Customer = c, Product = o.Product })
.ToList();
Then you can access you result object as a collection of anonymous objects where you have the Customer property and Product which has your entities.
Related
Is there a way to add elements to a List when doing this:
var Foo = new MyClass() {
PropertyList = MyList,
Id = Id,
}
I would like to add elements to PropertyList. For example would be the same as: MyList.Add()
The problem is that i do not have a list called MyList but i rather have elements that i want to append to PropertyList
Updating code based on comments:
var result1 = await query
.GroupBy(c => new {
c.CommissionId, c.ActivityId
})
.Select(grp => new RegistrationStatisticViewModel() {
CommissionId = grp.Key.CommissionId,
CommissionCode = grp.First().Commission.Code,
CommissionDescription = grp.First().Commission.Description,
MinuteWorked = grp.Sum(c => c.MinuteWorked),
ActivityId = grp.Key.ActivityId,
ActivityCode = grp.First().Activity.Code,
ActivityDescription = grp.First().Activity.Description,
})
.ToListAsync();
var grps = from d in result1
group d by d.CommissionId
into grp
select new RegistrationStatisticViewModel() {
CommissionId = grp.Key,
ActivityList = new List < Activity > {
new Activity {
//ActivityId = grp.Select(d => d.ActivityId),
//Code = grp.Select(d => d.ActivityCode),
//Description = grp.Select(d => d.ActivityDescription),
}
},
CommissionCode = grp.First().CommissionCode,
CommissionDescription = grp.First().CommissionDescription,
MinuteWorked = grp.First().MinuteWorked
};
return grps;
To give context:
forget the result1 is just some data i retrieve from my database
Commission is one class and contains:
CommissionId
Code
Description
Activity is one class and contains:
ActivityId ==> type GUID
Code ==> type string
Description ==> type string
Now the var = grps is a LINQ that gets the data and then instatiates a new object (class) new RegistrationStatisticViewModel()
So the tricky part we were discussing before is when i populate ActivityList with multiple activities.
When populating the list if i use .First() or .Select() i would only get one instance and therfore the list would only have one activity.
It worked when using .ToArray() for example if i replace ActivityList with just the ActivityId of type string (so a new property on RegistrationStatisticViewModel that is not a list anymore):
I can do this ActivityId = grp.Select(d2 => d2.ActivityId).ToArray()
And it will give me an array of all the ActivityId linked to that commissionId
I am sorry if this is confusing but it is for me as well. I would thank you if you could help me. No worries if you can't you have already give me very helpful answers, so i thank you for that!
Based on your remarks, I believe this is what you are trying to achieve:
public class PersonContainer
{
public IList<Person> Persons { get; set; }
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
var personContainer = new PersonContainer
{
Persons = new List<Person>
{
new Person
{
Name = "John Doe",
Age = 28,
},
new Person
{
Name = "Jane Doe",
Age = 27,
},
}
};
Here, the Persons property of PersonContainer is initialized and populated with Person elements during instantiation.
Let's assume I have multiple db tables, I'll just represent them as lists for convenience:
EntitySource {
public int Id {get; set;}
public ICollection<Entity_1> table_1 { get; set }
public ICollection<Entity_2> table_2 { get; set }
public ICollection<Entity_3> table_3 { get; set }
}
Entity_1/Entity_2/Entity_3 {
public int Id { get; set; }
public string Name { get; set; }
}
List<Entity_1> table1 = new List<Entity_1>() {new Entity_1{Id = 1, Name = "First"}, new Entity_1{Id = 2, Name = "Second"}
List<Entity_2> table2 = new List<Entity_2>() {new Entity_2{Id = 3, Name = "First"}, new Entity_2{Id = 4, Name = "Second"}
List<Entity_3> table3 = new List<Entity_3>() {new Entity_3{Id = 5, Name = "First"}, new Entity_3{Id = 6, Name = "Second"}
I'm querying against EntitySource which contains references to multiple collections that I want to query against and map to MergedList class that contains two properties, Id of the entity source and one collection containing all merged collections of the EntitySource.
What I want to achieve is query for only id's and map them to single list of integers.
Something like this:
var entities = await entitySource.Queryable()
.Select(e => new MergedList()
{
PrincipalId = e.Id,
CombinedIds = e.table1.Select(e => e.Id)
.Concat(e.table2.Select(e => e.Id)
.Concat(e.table3.Select(e => e.Id)
})
.ToListAsync(cancellationToken);
public class MergedList {
public int PrincipalId {get;set;}
public IEnumerable<int> CombinedIds {get;set;}
}
But apparently the above statement is not working, expression could not be parsed.
Unable to translate a collection subquery in a projection since either
parent or the subquery doesn't project necessary information required
to uniquely identify it and correctly generate results on the client
side.
I'm using Entity Framework Core v6.0
You can combine them on the client side.
var filtered = entitySource.Queryable()
.Where(ent => input.Id == ent.Id);
var rawData = await
filtered.SelectMany(e => e.table1.Select(t => new { e.Id, SubId = t.Id } ))
.Concat(filtered.SelectMany(e => e.table2.Select(t => new { e.Id, SubId = t.Id } ))
.Concat(filtered.SelectMany(e => e.table3.Select(t => new { e.Id, SubId = t.Id } ))
.ToListAsync(cancellationToken);
var entities = rawData.GroupBy(x => x.Id)
.Select(g => new MergedList()
{
PrincipalId = g.Key,
CombinedIds = g.Select(x => x.SubId).ToList()
})
.ToList();
So I am fairly new to LINQ and have ran into an issue that I have not been able to find a solution for.
I was reading through the LINQ guide on msdn when I saw an article on Group Joins.
https://learn.microsoft.com/en-us/dotnet/csharp/linq/perform-grouped-joins
I read through the page and thought that it was exactly what I needed to complete my query. For my query, I am calling Table A which includes an ID that I use to join with a contacts table. The ID from the contacts table is then used to join with Table C on the same ID. Table C holds a Child ID that is then used to join back with the contacts table to retrieve a list of contacts. The contacts primary ID's are used to join with a phone number table. Contacts can have multiple phone numbers.
var query = (from a in db.TableA
join b in db.Contacts on a.PrimaryID equals b.PrimaryID
join c in db.tableC on b.PrimaryID equals c.ParentPrimaryID
join d in db.Contacts on c.ChildID equals d.PrimaryID
join e in db.TablePhoneNbrs on d.PrimaryID equals e.PrimaryID into gj
where a.PrimaryID == id
select new
{
PrimaryId = d.PrimaryId,
FirstName = d.FirstName,
LastName = d.LastName,
phhoneNbrs = gj
});
So from the article, I read that if you join two tables and then call "into" after the join, it will store the results of the query into whatever variable you specify as a collection. So in the query above, I tried joining the individual contacts with their single/multiple phone number(s) and then calling "into" to return a collection, instead of duplicating the contact for each number, but it failed. Instead of returning a collection of phone numbers for contacts with multiple numbers, it just duplicated the contact for each number that was returned.
So then I tried reducing the query and instead using a specific contact ID number and testing it out with just a single result.
var query2 = (from a in db.Contacts
join b in db.TablePhoneNbrs on a.PrimaryID equalsb.PrimaryID into gj
where a.PrimaryID == 1234
select new
{
PrimaryID = a.PrimaryID,
FirstName = a.FirstName,
LastName = a.LastName,
phhoneNbrs = gj
}).ToList();
And this worked! So when I executed the query with a single contact ID, it correctly returned the contact and their two phone numbers as an array attached to the one contact object.
My question is if I am doing something wrong with the first query that is causing it to fail?
UPDATE: With a much better example!
So this is pretty much exactly how the relations work with the tables. This example appears to work, though. Query2 is the one that fails me at work. When it returns a contact, instead of storing the number in a collection and assigning it to Number variable, it duplicates the contact for each number that it has.
class Contact
{
public int primaryID { get; set; }
public string name { get; set; }
}
class TableC
{
public int parentID { get; set; }
public int childID { get; set; }
}
class TablePhoneNbr
{
public int primaryID { get; set; }
public string phoneNbr { get; set; }
}
class TableEmail
{
public int primaryID { get; set; }
public string email { get; set; }
}
class Program
{
static void Main(string[] args)
{
Contact mainContact = new Contact { primaryID = 1, name = "My Test Code" };
Contact Jim = new Contact { primaryID = 2, name = "Jim" };
Contact Bob = new Contact { primaryID = 3, name = "Bob" };
Contact Ashley = new Contact { primaryID = 4, name = "Ashley" };
Contact Mary = new Contact { primaryID = 5, name = "Mary" };
TableC child1 = new TableC { parentID = 1, childID = 2 };
TableC child2 = new TableC { parentID = 1, childID = 3 };
TableC child3 = new TableC { parentID = 1, childID = 4 };
TableC child4 = new TableC { parentID = 1, childID = 5 };
TablePhoneNbr Nbr1 = new TablePhoneNbr { primaryID = 2, phoneNbr = "123456" };
TablePhoneNbr Nbr2 = new TablePhoneNbr { primaryID = 2, phoneNbr = "999999" };
TablePhoneNbr Nbr3 = new TablePhoneNbr { primaryID = 3, phoneNbr = "888888" };
TablePhoneNbr Nbr4 = new TablePhoneNbr { primaryID = 4, phoneNbr = "777777" };
TableEmail Email1 = new TableEmail { primaryID = 2, email = "Hello World" };
TableEmail Email2 = new TableEmail { primaryID = 3, email = "Goodbye World" };
TableEmail Email3 = new TableEmail { primaryID = 4, email = "Testing1" };
TableEmail Email4 = new TableEmail { primaryID = 5, email = "Testing2" };
// Create two lists.
List<Contact> contacts = new List<Contact> { mainContact, Jim, Bob, Ashley, Mary };
List<TableC> relations = new List<TableC> { child1, child2, child3, child4 };
List<TablePhoneNbr> numbers = new List<TablePhoneNbr> { Nbr1, Nbr2, Nbr3, Nbr4 };
List<TableEmail> emails = new List<TableEmail> { Email1, Email2, Email3, Email4 };
// Create a list where each element is an anonymous type
// that contains the person's first name and a collection of
// pets that are owned by them.
var query = from primary in contacts
join relation in relations on primary.primaryID equals relation.parentID
join person in contacts on relation.childID equals person.primaryID
join number in numbers on person.primaryID equals number.primaryID into gj
select new { FirstName = person.name, Number = gj };
foreach (var v in query)
{
// Output the owner's name.
Console.WriteLine("{0}:", v.FirstName);
// Output each of the owner's pet's names.
foreach (TablePhoneNbr number in v.Number)
Console.WriteLine(" {0}", number.phoneNbr);
}
var query2 = from primary in contacts
join relation in relations on primary.primaryID equals relation.parentID
join person in contacts on relation.childID equals person.primaryID
join email in emails on person.primaryID equals email.primaryID
join number in numbers on person.primaryID equals number.primaryID into gj
select new { FirstName = person.name, Number = gj, Email = email.email };
foreach (var v in query2)
{
// Output the owner's name.
Console.WriteLine("{0}:", v.FirstName);
Console.WriteLine("{0}:", v.Email);
// Output each of the owner's pet's names.
foreach (TablePhoneNbr number in v.Number)
Console.WriteLine(" {0}", number.phoneNbr);
}
Console.ReadLine();
}
}
Try pulling out your contacts and using Distinct() before you try to get their numbers:
var contacts = (from a in db.TableA
where a.PrimaryID == id
join b in db.Contacts on a.PrimaryID equals b.PrimaryID
join c in db.tableC on b.PrimaryID equals c.ParentPrimaryID
join d in db.Contacts on c.ChildID equals d.PrimaryID
select new { d.PrimaryID, d.FirstName, d.LastName } ).Distinct();
var query = (from d in contacts
join e in db.TablePhoneNbrs on d.PrimaryID equals e.PrimaryID into ej
select new {
PrimaryId = d.PrimaryID,
FirstName = d.FirstName,
LastName = d.LastName,
phhoneNbrs = ej
});
Note it may be be better to just run Distinct against the PrimaryIDs and then lookup the FirstName and LastName, but that should run on the SQL side so I don't think it matters a lot.
I'm trying to test out a dynamic join extension method as defined here to join two datasets(dataset1 and dataset2) on multiple conditions. My join condition is as shown below
outerSelector = "new ( dataset1.ToBeReconciled as col1, dataset1.TransactionDate as col2)";
innerSelector = "new ( dataset2.ToBeReconciled as col1, dataset2.TransactionDate as col2)";
This does not result in any error, but at the same time always returns zero records, even though I have records that match this condition.
Any idea how to make this work? Thanks!
Perhaps you should start with a simple example, and then try to work through what you have there... I've composed a simple to understand one below..
void Main()
{
var fruits = new List<Fruit>
{
new Fruit{ GroceryId = 1,Name = "Apple", ProductId = 1},
new Fruit{ GroceryId = 1,Name = "Orange", ProductId = 2},
};
var groceries = new List<Grocery>
{
new Grocery { GroceryId = 1, Name = "Fruits and Vegetables" },
new Grocery { GroceryId = 2, Name = "Drinks and snacks" },
};
var joinedResults = fruits.Join(groceries, // References the groceries declared above,
fruit => fruit.GroceryId, // Join by GroceryId located on the Fruit
grocery => grocery.GroceryId, // Join by the GroceryID located on Grocery
(product, grocery) => new
{
ProductId = product.ProductId,
ProductName = product.Name,
GroceryName = grocery.Name
});
}
public class Fruit
{
public int ProductId { get; set; }
public int GroceryId { get; set; }
public string Name { get; set; }
}
public class Grocery
{
public int GroceryId { get; set; }
public string Name { get; set; }
}
I am new to LINQ and sorry if my question have been asked
I have 2 classes
public class Person
{
int ID {get;set;}
string FirstName {get;set;}
string LastName {get;set;}
}
and
public class House
{
int ID {get;set;}
string Address {get;set;}
string ZipCode {get;set;}
int PersonId {get;set;}
}
I am saving the list of houses in a IEnumerable List
IEnumerable<House> ListHouses = GetAllHouses();
GetAllHouses return the list of houses from the database
I want to use Lamda select in LINQ in order to do the following
var st = ListHouses .Select(h => new
{
id = h.ID,
Address= h.Address,
Zip= h.ZipCode ,
PersonFirstName = GetPersonByID(h.PersonId ).FirstName,
PersonLastname = GetPersonByID(h.PersonId ).lastname
});
Where GetPersonByID returns an object of Type Person that has the given ID. and then I take his first name and last name.
My question is this:
Instead of Getting the Person 2 times for the variables (personFirstName and PersonLastName) Is there a way I can get it one time and then used it. Something like
PersonForId = GetPersonByID(h.PersonId)
PersonFirstName = PersonLastName.FirstName,
PersonLastname = PersonLastName.lastname
I'm looking for something similar to Join in SQL where you join a value from another table.
Thanks you very much for any help
You're extremely close! Using your code (and making all properties on House and Person public), here is a method using the LINQ Join method:
var st = GetAllHouses().Join(GetAllPersons(),
outerKey => outerKey.PersonId,
innerKey => innerKey.ID,
(house, person) => new
{
house.ID,
house.Address,
house.ZipCode,
PersonFirstName = person.FirstName,
PersonLastname = person.LastName
});
Note: I would recommend the GetAllPersons() and the GetAllHouses() methods return IQueryable rather than IEnumerable. Doing so will build the expression (including the join), which means LINQ-to-SQL (or Entities) will build a proper SQL statement with the JOIN included, instead of enumerating the collections and then joining.
Additional information on such can be found here: Returning IEnumerable<T> vs. IQueryable<T>
using System;
using System.Linq;
class Customer
{
public int ID { get; set; }
public string Name { get; set; }
}
class Order
{
public int ID { get; set; }
public string Product { get; set; }
}
class Program
{
static void Main()
{
// Example customers.
var customers = new Customer[]
{
new Customer{ID = 5, Name = "Sam"},
new Customer{ID = 6, Name = "Dave"},
new Customer{ID = 7, Name = "Julia"},
new Customer{ID = 8, Name = "Sue"}
};
// Example orders.
var orders = new Order[]
{
new Order{ID = 5, Product = "Book"},
new Order{ID = 6, Product = "Game"},
new Order{ID = 7, Product = "Computer"},
new Order{ID = 8, Product = "Shirt"}
};
// Join on the ID properties.
var query = from c in customers
join o in orders on c.ID equals o.ID
select new { c.Name, o.Product };
// Display joined groups.
foreach (var group in query)
{
Console.WriteLine("{0} bought {1}", group.Name, group.Product);
}
}
}
Output
Sam bought Book
Dave bought Game
Julia bought Computer
Sue bought Shirt