I have built a short and sweet join query to try and get a feel on how to create a join. I managed to do it in SQL. But I'm not sure how to do it in LINQ.
LINQ:
public IQueryable<DepartmentBreakdownReport> GetDepartmentBreakdown
(int SupplierID, int ReviewPeriodID)
{
return (from detail in camOnlineDb.Details
join suppDepp in camOnlineDb.SuppDepts
on new { detail.ClientID, detail.CategoryID }
equals new { suppDepp.ClientID, suppDepp.CategoryID }
select detail.ClientID + "" + detail.CategoryID);
}
Edit: Ignore the parameters which are brought in, I will cater to those once I have my join working.
You are returning an IQueryable<string> rather than what I assume you want is IQueryable<DepartmentBreakdownReport>. To return that type, you need to project in the select by specifying the type, something like this:
return (from detail in camOnlineDb.Details
join suppDepp in camOnlineDb.SuppDepts
on new { detail.ClientID, detail.CategoryID }
equals new { suppDepp.ClientID, suppDepp.CategoryID }
select new DepartmentBreakdownReport
{
Property1 = detail.Property1,
//your properties here
});
The problem was that Category ID was nullable in Detail but not in suppDepp.
To fix it I changed it from a non-nullable type
Related
I have this code:
public class ExistedProducts
{
public int productID{get;set;}
public int productQte{get;set;}
}
..
..
..
public List<ExistedProducts> GetStock()
{
var result = from p in Products
join st in Stock on st.ProductID equals p.ID
select new{ExistedProductID=p.ID,ExistedProductQte = st.Qte};
return result.Cast<ExistedProducts>.ToList();// exception here
}
My first question, can I directly produce the typed collection from the query?
If not, how can I do the casting (i called the Cast() method but a raised exception saying impossible to do cast from
'<>f__AnonymousType0`2[System.Int32,System.Int32] ?
I want to avoid the copy by loop!
Yes instead of projecting anonymous type you can directly project your type ExistedProducts like this:-
var result = (from p in Products
join st in Stock on st.ProductID equals p.ID
select new ExistedProducts
{
productID = p.ID,
productQte = st.Qte
}).ToList();
return result;
I'm trying to create a function to grab a List<>() of type "tableContact" which is an entity (sort of like when you do a simple select statement: query.ToList();)
But this is becoming frustrating because I kept getting "null object reference" errors. For some reason "join" statement doesn't work, so I tried an alternate linq statement.
I have an Object2Contacts table that I want to LEFT JOIN and I'm looking up my Object and trying to see all the contacts for this Object. I also can't figure out how to change an "anonymous type" back into an entity table.
Also not every object has contacts, so sometimes null List<> should be returned.
public List<tableContact> getContactsForObject(int oid)
{
if (oid > 0)
{
var query = (from s in entities.tableContacts
from o in entities.tableObject2Contacts
where s.contact_id == o.contact_id
where o.object_id == oid
select new { s });
if (query != null)
{
IEnumerable<tableContact> e = (IEnumerable<tableContact>)query.ToList();
return (List<tableContact>)e;
}
}
return new List<tableContact>();
}
I want to then loop through the object returned... e.g.:
foreach ( tableContact c in MyList){
WriteLine(c.Name);
}
EDIT
I also tried:
List<tableContacts> contacts = (from s in entities.tableContacts
join o in entities.tableObject2Contacts
on s.contact_id equals o.contact_id
where o.object_id == oid
select s).ToList();
Then I can't convert it back into a List and still "null reference".
EDIT 2
Yes the query I am running may definitely bring in an "empty" list. I don't mind empty lists, but it shouldn't give "object null reference."
I would write the join statement a little bit different:
var query = (from s in entities.tableContacts
join o in entities.tableObject2Contacts
on new { ContactID = s.contact_id, ObjectID = oid }
equals new { ContactID = o.contact_id, ObjectID = o.objectID }
into oTemp
from o in oTemp.DefaultIfEmpty()
select new { s });
This would be a proper left-join using linq.
Maybe your NullReferenceException is caused by a wrong join or something.
Nevermind, The "I also tried this" is actually correct code, but for some reason I hadn't established my entities properly so that was returning null.
Although I'm still super confused about "anonymoustypes" I wouldn't know how to make a function that returns "anonymoustype".
I have writting a LINQ query to fill a listview but it useses the .ToString() method which apparetly is not allowed. When I use the below code I get the error message:
Error: LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression
Is there a way to use the ToString() in LINQ or if that is not possible what is the solution to converting a DateTime to String in the query. Please knot that ReleaseDateName is a string and ReleaseDate is a DateTime
using (var db = new ReleaseInfo())
{
lvReleaseInfo.DataSource = (from r in db.MediaReleases
join rn in db.ReleaseNames
on new { MediaReleaseID = r.MediaReleaseID, CultureCodeID } equals new { rn.MediaReleaseID, rn.CultureCodeID }
join plat in db.MediaPlatforms
on new { MediaPlatformID = r.MediaPlatformID, CultureCodeID } equals new { plat.MediaPlatformID, plat.CultureCodeID }
join pub in db.MediaPublishers
on new { MediaPublisherID = r.MediaPublisherID, CultureCodeID } equals new { pub.MediaPublisherID, pub.CultureCodeID }
join c in db.Countries
on new { CountryID = r.CountryID, CultureCodeID } equals new { c.CountryID, c.CultureCodeID }
join rd in db.ReleaseDates
on new { MediaReleaseID = r.MediaReleaseID, CultureCodeID } equals new { rd.MediaReleaseID, rd.CultureCodeID }
join a in db.AffiliateLinks
on new { MediaReleaseID = r.MediaReleaseID, CultureCodeID } equals new { a.MediaReleaseID, a.CultureCodeID }
where r.SectionID == SectionID
select new
{
rn.ReleaseTitle,
plat.MediaPlatformName,
pub.MediaPublisherName,
c.CountryName,
ReleaseDate = (rd.ReleaseDate == null ? rd.ReleaseDateName : rd.ReleaseDate.ToString()),
a.AffiliateLinkAddress
}).ToList();
lvReleaseInfo.DataBind();
}
Since you are materializing your query to list anyway, you could do the conversion on the .NET side, rather than in the RDBMS, like this:
...
select new {
rn.ReleaseTitle,
plat.MediaPlatformName,
pub.MediaPublisherName,
c.CountryName,
rd.ReleaseDateName,
rd.ReleaseDate,
a.AffiliateLinkAddress
}).AsEnumerable() // <<== This forces the following Select to operate in memory
.Select(t => new {
t.ReleaseTitle,
t.MediaPlatformName,
t.MediaPublisherName,
t.CountryName,
ReleaseDate = t.ReleaseDateName ?? t.ReleaseDate.ToString()
t.AffiliateLinkAddress
}).ToList();
Since the ToString() is called on an element from IEnumerable<T>, it will no longer fail. Also note the use of ?? operator in place of a null-checking ? : conditional.
The problem is that you can't call ToString() on a field until it's been deserialized. So, rather than trying to call ToString() in the query, simply do it on the results afterwards.
In the database the value you're operating on has no notion of ToString() which is why you get the error. The query may look and feel like C# code but keep in mind that under the covers that is being transformed to a SQL query like any other. After you get the list back you can write a very simple LINQ query to solve the problem.
I am getting values from different tables i var type and I want to return them. What should be the return type of the function:-
public void getlist()
{
try
{
using (ShowDataToClientDataContext c = new ShowDataToClientDataContext())
{
var recList = (from record in c.GetTable<T_RECORDSHOW>()
where record.RecordStatus.Equals(RecordStatus.Active)
select new
{
Student = (from stu in c.T_STUDENTSHOWs
where stu.Id.Equals(record.StudentId)
select stu.Name).Single().ToString(),
Trade = (from t in c.T_TRADESHOWs
where t.Id.Equals(record.TradeId)
select t.Name).Single().ToString(),
SessionId = (from s in c.T_SESSIONSHOWs
where s.Id.Equals(record.SessionId)
select s.Name).Single().ToString(),
Month = record.Month.ToString(),
Attendance = record.Attendance.ToString(),
}).ToList();
return recList;
}
}
catch
{
}
}
anybody there to help me?
var isn't a type in itself. It just asks the compiler to infer the type of the local variable.
Now in your case, the type is a List<T> where the T is an anonymous type. If you want to be able to use the properties within the elements of the list from other code, you'll need to either do so dynamically (ick) or turn the anonymous type into a full, named type. Anonymous types are really only designed to be used from the methods where the objects are created. You can then return a List<DenormalizedRecord> or whatever.
Also note that your query would be much simpler if you'd just use joins:
from record in c.GetTable<T_RECORDSHOW>()
where record.RecordStatus.Equals(RecordStatus.Active)
join student in c.T_STUDENTSHOWs on record.StudentId equals student.Id
join trade in c.T_TRADESHOWs on record.TradeId equals trade.Id
join session in c.T_SESSIONSHOWs on record.SessionId equals session.Id
select new DenormalizedRecord {
Student = student.Name,
Trade = trade.Name,
SessionId = session.Name, // Confusing property name, by the way
Month = record.Month.ToString(), // Why the ToString()?
Attendance = record.Attendance.ToString() // What the ToString()?
}
It's not totally true that you cannot return anonymous types from a method, and I don't mean using tricky stuff with reflection. You just have to move the burden of instantiation to the caller:
IEnumerable<T> getlist<T>(Func<string, string, string, string, string, T> resultor)
{
try
{
using (ShowDataToClientDataContext c = new ShowDataToClientDataContext())
{
var recList = (from record in c.GetTable<T_RECORDSHOW>()
where record.RecordStatus.Equals(RecordStatus.Active)
select resultor
(
(from stu in c.T_STUDENTSHOWs
where stu.Id.Equals(record.StudentId)
select stu.Name).Single().ToString(),
(from t in c.T_TRADESHOWs
where t.Id.Equals(record.TradeId)
select t.Name).Single().ToString(),
(from s in c.T_SESSIONSHOWs
where s.Id.Equals(record.SessionId)
select s.Name).Single().ToString(),
record.Month.ToString(),
record.Attendance.ToString()
)).ToList();
return recList;
}
}
catch
{
}
}
Type inference works like a charm, so you can call your method like this:
var list = getlist((st, tr, sid, m, att) => new
{
Student = st,
Trade = tr,
SessionId = sid,
Month = m,
Attendance = att
});
No need to define any DTO class just for the sake of outputting those results.
PS: the query itself could be better, but I'm just tackling the problem in your question.
You can't return an anonymous type from a method (perhaps with some very technical workarounds).
You should probably create a class with the properties that you want returned, and then return an object of that class.
Create a custom class. Use it as return type
select new CustomClass
{
Propery1 = YourSelectedPropery1
, Propery2 = YourSelectedPropery2
}
I've noted that you can use some generic parameter in order to solve your problem.
Change method signature to:
public List<TReturn> getlist<TReturn>()
And change your ToList<ClassName>() to ToList<TReturn>.
This will enable your method to return lists of any type (supported by your model, of course!).
In my Linq, I am trying to make an inner join to a nullable field. Employee and Department have a relation, Department may have an EmployeeID or may have a null. So what would be my join, if i want only the records that satisifed the inner join (no result for null EmployeeIDs):
var result = from emp in employees
join dept in departments
on new { Source = emp.EmployeeID }
equals new { Source = dept.EmployeeID };
I am getting an exception:
The type of one of the expressions in the join clause is incorrect.
Type Inference failed in a call to 'join'.
Thanks
To compare Int? and Int, append .Value to the nullable property:
var result = from emp in employees
join dept in departments
on new { Source = emp.EmployeeID }
equals new { Source = dept.EmployeeID.Value };
What if you reverse your join and put a little where in there?
var result = from department in departments
where department.EmployeeID != null
join employee in employees
on department.EmployeeID.Value equals employee.EmployeeID
select new { employee, department };
Found a useful answer from another link at https://social.msdn.microsoft.com/Forums/en-US/bf98ec7a-cb80-4901-8eb2-3aa6636a4fde/linq-join-error-the-type-of-one-of-the-expressions-in-the-join-clause-is-incorrect-type-inference?forum=linqprojectgeneral
To join multi-valued keys you need to construct an anonymous typ on both sides of the 'equals' that is the same type. The anonymous type initializer expression infers both type and name of members from the expression you supply. In your case the names of the members are different so the types end up being different so C# cannot figure out the common type between the two.
on new { VC.Make, VC.Model } equals new { MD.MakeID, MD.RefNum }
should be
on new { VC.Make, CV.Model } equals new { Make = MD.MakeID, Model = MD.RefNum }
Using the name = value syntax in the initializer you can specify the name the compiler uses when creating the type. If all members types & names are the same then the anonymous types are the same type.
Check the type on emp.EmployeeID and dept.EmployeeID. You might be missing a cast if they are different.
something like:
on new { Source = emp.EmployeeID }
equals new { Source = **(int)**dept.EmployeeID };
Looks like emp.EmployeeID is of type int and dept.EmployeeID is of type nullable<int>.
I had the same issue, where my charge_codes.CompanyId was nullable but my order_items.CompanyId was NOT nullable.
So I had to get my charge codes into their own ananomous type and make it not be nullable.
var chargeCodes = from s in db.Charge_Codes
where s.CompanyID != null
select new { CompanyID = (int)s.CompanyID,
Charge_CodeID = s.Charge_CodeID,
Revenue_Code_Id = (int)s.Revenue_CodeID, };
//now my chargeCodes contains an anonymous with a non nullable CompanyID and
//a non nullable Revenue_CodeID
//use chargeCodes here
var query = from oi in db.Order_Items
join cc in chargeCodes on
new {oi.CompanyID, oi.Charge_CodeID} equals new {cc.CompanyID, cc.Charge_CodeID}
In my scenario I had this error on a join using multiple columns. The property names were different and one of them was also nullable. All I did was creating a name to those properties and adding the ".Value" on the nullable value so the LINQ Join could correctly associate those properties.
var query = from y in Context.Table1
join y in Context.Table2 on new { Field1 = x.Field1.Value, Field2 = x.Field2 }
equals new { Field1 = y.Field1DiffName, Field2 = y.Field2 }
I hope it helps whoever is facing this issue.