What is the logic here with LINQ C# query? [closed] - c#

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
Check the following program below from the book "Essential LINQ":
class Customer
{
public string CustomerID {get;set;}
public string ContactName {get;set;}
public string City {get;set;}
public static List<Customer> GetCustomers()
{
return new List<Customer>
{
new Customer {CustomerID = "ALFKI", ContactName = "Maria Anders", City = "Berlin"},
new Customer {CustomerID = "ANATR", ContactName = "Sns Trujillo", City = "Mexico D.F."},
new Customer {CustomerID = "ANTON", ContactName = "Antonio Moreno", City = "Mexico D.F."}
};
}
}
void Main()
{
var query = from c in Customer.GetCustomers()
where c.City == "Mexico D.F."
select new { c.City, c.ContactName};
foreach (var cityandcontact in query)
{
Console.WriteLine(cityandcontact);
}
}
In the LINQ Query, why it gives me error if I remove "new" from line:
select new {c.City, c.ContactName};
why we can't just write like this
select c.City, c.ContactName;
what is the logic here?

Queries return enumerations of objects of the same class. It can be any class, but it needs to be just one for all rows. You cannot return pairs of objects (a city and a contact name) without combining them into a single object. In this case, you are combining them into an object of anonymous type, with two properties.
On a side note, there is no advantage to using Select method at all, because both properties come from the same Customer class. In fact, there is less efficient than returning customer objects unchanged, like this:
var query = from c in Customer.GetCustomers()
where c.City == "Mexico D.F.";
foreach (var c in query)
{
Console.WriteLine("{0} {1}", c.City, c.ContactName);
}

LINQ methods, like other C# methods, can only return one value/object. (There is no syntax support added for said hypothetical construct to magically do what the new { .. } stuff does.)
This is why the different fields are "wrapped" in an new object: it is then a single value/object with members representing all the selected fields.
(Likewise, the final result, an IEnumerable<..>, is also just one value/object with 0 or more elements in the sequence: in this case each element is a new object created with new { .. } above.)

new { c.City, c.ContactName}; is the C# syntax for an anonymous type.

The 'select' selects a Customer class, which consists of a City variable and a ContactNamr variable. So, you have to provide select with a new class with those variables

This is not SQL this is linq, and the syntax is basically what you see.
select new { c.City, c.ContactName};
limits the output of the query to a type that contains just the City and the ContactName.
You may ask what type is this? Well it's an anonymous type that the compiler creates for you.
The code then iterates over the results of the query (IEnumerable<this_new_type>) and writes the ToString() of this new type.

select new is creating a new anonymous object.
"Anonymous types provide a convenient way to encapsulate a set of read-only properties into a single object without having to explicitly define a type first"
select new {c.City, c.ContactName};
You could also create a concrete class to project into.
i.e a class called Blah:
class Blah
{
public string City {get;set;}
public string ContactName {get;set;}
}
... [rest of query]
select new Blah {c.City, c.ContactName};
The reason you cannot go "select c.City, c.ContactName;", is because the language syntax is not designed to handle it.

Related

How to return a string and a list of elements together in c#?

Is there any way to return a string parameter and a list to the method in c#?
List<cCountry> countries = new List<cCountry>();
countries = GetCountries(userProfile.Country);
private List<cCountry> GetCountries(string p)
{
inputCollection = new cDTOCollection<cDTOBase>();
outputCollection = new cDTOCollection<cDTOBase>();
outputCollection = UpdateProfileBizobj.ProcessRequest(ActionConstants.ActionGetCountriesList, null);
List<cCountry> countries = new List<cCountry>();
cDTOSingleValue SelectedCountryID = new cDTOSingleValue();
foreach (cDTOCountry countryItem in outputCollection)
{
if (p == countryItem.CountryName)
SelectedCountryID.Id = countryItem.CountryID;
countries.Add(Mapper.Map<cDTOCountry, cCountry>(countryItem));
}
countries.Remove(countries[0]);
return countries;
}
Like in the method above I need to return a parameter
SelectedCountryID and also the countries list.Is there any way to
return both?
populate and return an object instead.
public class ReturnObject
{
public List<cCountry> Countries { get; set; }
public guid SelectedCountryID { get; set; } // don't think you defined what type SelectedCountryID is in your question
}
But if you find yourself needing to return more than 1 thing, it's probably an indication that your method is doing too much and should be refactored.
Why can't you reuse the value that you are sending to the method?
return Tuple.Create(new List<Country>(),"astring")
Answer to your question
You can also use the out modifier on a parameter to pass by reference, which would let the method modify the resulting object, effectively returning it. That's a pretty bad design for most cases though, and you probably refactor your methods into smaller pieces or wrap things up into better objects.
In your code:
private List<cCountry> GetCountries(string p, out cDTOSingleValue SelectedCountryID)
{
//your code
}
Potential Refactoring
Looking at your code it, seems your really are trying to do two separate things.
Getting Countries and mapping them
Finding the last country whose name matches the parameter passed in
So as long as your country list isn't ridiculously large, making two separate method calls will make your code more readable and more maintainable. I like using LINQ to manipulate the in-memory collections.
I'd personally use one method to fetch the data.
private List<cDTOCountry> GetCountries()
{
inputCollection = new cDTOCollection<cDTOBase>();
outputCollection = new cDTOCollection<cDTOBase>();
return UpdateProfileBizobj.ProcessRequest(ActionConstants.ActionGetCountriesList, null);
}
And then later I'd process the data as needed:
var preMappedCountries = GetCountries();
var mappedCountries = preMappedCountries
.Select(c => Mapper.Map<cDTOCountry, cCountry>(c)) //map the data
.Skip(1) //skip the first element (the remove index 0)
.ToList(); //cast to List. Read more on LINQ's deferred execution.
var lastMatchingName = preMappedCountries
.LastOrDefault(c => c.Name == p); //gets the last country with matching name
The benefit to separating the logic into pieces is potential reuse of methods. If you ever find yourself needing to get data without mapping, you can do just that and skip all the LINQ logic. This way the logic that gets data is distinct from the logic that matches country names.
In your case an out param seems more appropriate. Otherwise as Kevin suggested you can return a Tuple.

A better way than generic list of anonymous type

So I have an sqlite database with [Raw_Data] and [Names] tables. Raw_Data has 3 fields that hold a reference (foreign key?) to the Names table (requester, worker, and approver).
When I display data (dgvResults is a DataGridView in a Windows Forms application), I want to merge the names into the main table (Raw_Data).
I am using sqlite-net (by praeclarum on guitub) and have this code (only relevant parts shown for brevity):
...
using (var db=new SQLiteConnection(DB_Interop_SQLite.DB_Path, true))
{
this.Users=db.Table<User>().ToList<User>();
this.Records=db.Table<Raw_Data>().ToList<Raw_Data>();
this.Roles=db.Table<Role>().ToList<Role>();
}
var items=
(
from r in this.Records
join requester in this.Users on r.Requester equals requester.ID into group1
from requester in group1.DefaultIfEmpty()
join worker in this.Users on r.Drafter equals worker.ID into group2
from worker in group2.DefaultIfEmpty()
join approver in this.Users on r.Approver equals approver.ID into group3
from approver in group3.DefaultIfEmpty()
select new {
r.ID, r.Project, Requester=requester, r.Task_Code,
r.DT_submitted, r.DT_required, // other fields
Worker=worker, r.DT_completed, // other related fields
Approver=approver, r.DT_approved, // more fields
}
).ToList();
this.dgvResults.DataSource=items;
...
I have read through LINQ Join 2 List<T>s and Create Items from 3 collections using Linq and Merge multiple Lists into one List with LINQ
They have been a great help.
I also referred to A generic list of anonymous class, which really helped me create the linq query and it all works beautifully.
In my code, User class has ToString() method overwritten so it displays the full name just as I want.
Suppose I wanted a List that holds fields from Raw_Data, but instead of the integer field that refers to the ID from Names, I want the User object as a field, which will hold the ID as well as the rest of the user information (Name, email, phone, etc), just like I have in my anonymous type in the select statement.
So my question is: is there a better way to implement a list (that is not of the anonymous type), without rewriting the entire Raw_Data class just to have a "user" field (from Names table) rather than just the user id?
Ideally, I want the exact same behaviour as my code, but preferably without the anonymous type.
Thanks.
Not sure if this what you're looking for, but you could specify a class just to hold that data, then select into that instead of an anonymous type:
public class RawDataInfo
{
public int ID { get; set; }
public string Requester { get; set; }
...
}
then alter your select RawDataInfo()
select new RawDataInfo(){
ID = r.ID,
Requester = requester,
...
}
You may want to look into something like AutoMapper. This is a library that allows you to easily and consistently map from one type of object to another. It's clean and well tested.

Find if field in one Enumerable exists in two possible fields of another

I have two enumerables made up of different types.
public Contact
{
public string fullName;
}
public Property
{
public string Rep;
public string PropMgr;
}
I'm trying to get all "Contacts" who are represented in either the Rep or PropMgr fields.
My intuition says join on rep for one result, then join on PropMgr for another result set. Then join the result sets and select distinct. Not sure if that will even work and if it will seems like there is a more efficient way.
Adding some additional information:
Some data would be
Contact
FullName: Nick
Property
Name: "Happy Place"
PropMgr: Nick
Rep: Sally
When comparing the two sets and I get to this combination, I want to select the contact "Nick".
Keeping in mind I have IEnumerable ContactsList and IEnumerable PropertyList
I don't have any data to test it, but I guess something like this should work:
IEnumerable<Contact> contacts = ...
IEnumerable<Property> properties = ...
var query = from property in properties
from name in new[] { property.Rep, property.PropMgr }
join contact in contacts on name equals contact.FullName
select contact;
var result = query.Distinct().ToList();
Try following Linq Query
Contacts.Select(x=>x.fullName).Intersect(Properties.Select (x=>x.Rep).Union(Properties.Select(x=>x.PropMgr))
// contacts -> IEnumerable of Contact, Properties -> IEnumerable of Property
So many different ways to solve the same problem...
Something a little lower-tech to try:
var namesInProperties = new HashSet<string>();
foreach (Property p in PropertyList)
{
namesInProperties.Add(p.PropMgr);
namesInProperties.Add(p.Rep);
}
IEnumerable<Contact> matchingContacts = ContactsList.Where(c => namesInProperties.Contains(c.fullName));

LINQ query returns duplicate despite Distinct()

Ive got the following query that binds to a DropDownList;
if (!Page.IsPostBack)
{
var branchTags =
(
from t in context.ContactSet
orderby t.py3_BranchArea
where t.py3_BranchArea != null
select new
{
BranchTagCode = t.py3_BranchArea,
BranchTag = (t.FormattedValues != null && t.FormattedValues.Contains("py3_brancharea") ? t.FormattedValues["py3_brancharea"] : null)
}
).Distinct();
ddlBranchTags.DataSource = branchTags;
ddlBranchTags.DataBind();
}
For some reason it still ourputs 2 rows that are visually the same. It might be the case that there are two enitites in the CRM with the same name. But, if Im using distinct on the query and only returning the 'py3_brancharea' then surely the Distinct should be run on the actual records returned?
So, this suggests to me -and my limited LINQ knowledge- that its because of the line:
BranchTagCode = t.py3_BranchArea
But, this needs to be called to make it possible to call the FormattedValues.
How then do I get a distinct set of results based purely on 'BranchTag' ?
If Distinct() is not working it is possibly a problem with the particular classes gethashcode() or equals() override methods, which are either not set up correctly or omitted entirely. In a custom class you will most likely need to specify these overrides to get Distinct() and other like methods to function correctly.
You could try to use a where or any clause to differentiate between duplicates as well. Which could be a work around for the Distinct() issues.
To further explain how to set up the Distinct() Method with custom classes. You will need to within the class that you are searching through set the override methods GetHashCode() and Equals(). These or Object level methods that should be in every single class no matter what. To start head to the class in question and type this:
public override bool Equals(object obj)
then
public override int GetHashCode()
Lets say you have this simple class before the overrides:
class foo{
int H {get;set;}
public foo(int _h){
H = _h;
}
}
It would now look like this:
class foo{
int H {get;set;}
int K {get;set;}
public override bool Equals(object obj){
if(obj == null) return false;
foo test = (foo)obj);
if(test == null) return false;
if(this.H == obj.H && this.K == obj.K) return true;
}
public override int GetHashCode(){
int hashH = H.GetHashCode();
int hashK = K.GetHashCode();
return hashH ^ hashK;
}
public foo(int _h){
H = _h;
}
}
Now you could use Distinct() on Ienumerable types containing the foo class like so:
List<foo> FooList = new List<foo>(Collection of 9 Foos);
var res = FooList.Distinct();
Another, much more simple way that worked for me, but may not work in all situations, is using this guys method ( GroupBy() and First()):
Finding Distinct Elements in a List
He creates a List<Customer> customers with FirstName and LastName. Then groups them all by FirstName and grabs the first element from each group!
`
List< Customer > customers = new List< Customer >;
{
new Customer {FirstName = "John", LastName = "Doe"},
new Customer {FirstName = "Jane", LastName = "Doe"},
new Customer {FirstName = "John", LastName = "Doe"},
new Customer {FirstName = "Jay", LastName = null},
new Customer {FirstName = "Jay", LastName = "Doe"}
};
`
Then:
`
var distinctCustomers = customers.GroupBy(s => s.FirstName)
.Select(s => s.First());
`
In my situation, I had to use FirstOrDefault() though.
Is it possible that the two results are different, do they have the same branch tag code and branch tag?
You could implement a custom equality comparer and pass it to distinct() so that it only compares the field that you want? it's a bit more difficult because of the anonymous type in your select statement, but this answer has a way around that.
The default equality comparison for anonymous types is case sensitive. Do the returned values you expect have different casing? As Matt suggested you may want to look at a custom IEqualityComparer implementation on a custom class otherwise.
I changed my code from
.Distinct().ToList();
to
.ToList().Distinct().ToList();
and now it's able to avoid the duplicate. Not sure what's the reason behind.
Another possibility it that the Entity Object has a define key that is not unique.

Linq to Sql DB Object to Domain Object mapping and performance

I'm having a problem trying to make my LINQ to SQL queries and the mapping to my domain objects DRY without incurring the cost of multiple round trips to the db. Given this example:
var query1 = from x in db.DBProducts
select new MyProduct
{
Id = x.ProductId,
Name = x.ProductName,
Details = new MyProductDetail
{
Id = x.DBProductDetail.ProductDetailId,
Description = x.DBProductDetail.ProductDetailDescription
}
}
The query will make ONE round trip to the DB. Great! However, the problem I see with this is that eventually, I'll also have a 'GetProductDetails' method which will also need to do some of the SAME "data object -> domain object" mapping, very similar to that above.
To alleviate some of the mapping, I thought it might be a cool idea to extend the partial data object classes to do the mapping for me, like so:
public partial class DBProduct
{
MyProduct ToDomainObject()
{
return new MyProduct
{
Id = this.ProductId,
Name = this.ProductName,
Details = this.DBProductDetails.ToDomainObject()
};
}
}
public partial class DBProductDetail
{
MyProductDetail ToDomainObject()
{
return new MyProductDetail
{
Id = this.ProductDetailId,
Description = this.ProductDetailDescription
};
}
}
Nice! Now, I could simply rewrite query1 as follows:
var query1 = from x in db.DBProducts
select x.ToDomainObject();
This makes the code more DRY and more readable. Additionally, other queries that need to do the same type of mapping can simply use the ToDomainObject() method for the mapping. It works, but with a cost. While watching via Profiler, the first query would call the db ONCE, joining tables where necessary. The second query doesn't join appropriately, thus making multiple calls to the DB. Is there a way to accomplish what I'm trying to do: refactor LINQ to SQL queries so that the mapping to domain objects is DRY (no code duplication)?
Use AutoMapper. Once you've tried it, it's unlikely you will ever see code like this:
new MyProduct
{
Id = x.ProductId,
Name = x.ProductName,
Details = new MyProductDetail
{
Id = x.DBProductDetail.ProductDetailId,
Description = x.DBProductDetail.ProductDetailDescription
}
}

Categories