anonymous type and multiple properties - linq

I have this error: An anonymous type cannot have multiple properties with the same name. Whether this can be resolved with alias ie, whether an alias exists in LINQ
var device_query = from d in DevicesEntities.device
join dt in DevicesEntities.devicetype on d.DeviceTypeId equals dt.Id
join l in DevicesEntities.location on d.Id equals l.DeviceId
join loc in DevicesEntities.locationname on l.LocationNameId equals loc.Id
where l.DeviceId == d.Id
select new {
d.Id,
d.DeviceTypeId,
d.SerialNumber,
d.FirmwareRev,
d.ProductionDate,
d.ReparationDate,
d.DateOfLastCalibration,
d.DateOfLastCalibrationCheck,
d.CalCertificateFile,
d.Notes,
d.TestReportFile,
d.WarrantyFile,
d.CertificateOfOriginFile,
d.QCPermissionFile,
d.Reserved,
d.ReservedFor,
d.Weight,
d.Price,
d.SoftwareVersion,
dt.Name,
dt.ArticleNumber,
dt.Type,
l.StartDate, //AS LastStartDate,
l.LocationNameId,
loc.Name //in this line I have problem
};

You need to provide alternative names for the duplicate properties. For example:
select new {
// ... other properties here ...
dt.Name,
dt.ArticleNumber,
dt.Type,
LastStartDate = l.StartDate,
l.LocationNameId,
CurrentLocation = loc.Name
};

It's a confligt on "Name"
You are mapping both dt.Name and loc.Name, both which the compiler tries to set to the "Name" property of the anon type.
change one of them to e.g. LoationName = loc.Name.
HTH
[edit]
Way too late to hit submit :-)

Related

Linq NOT EXISTS multiple tables

I want to do a LINQ NOT EXISTS on query MULTIPLE TABLES.
All examples on Google or SO are handling two tables I'm working with three so I'm struggling as a newbie on LINQ on how to reference them correctly.
First I tried this LINQ query
var nocertificates = (
from x in rmdb.t_certificates
from ce in rmdb.t_user_certificates
from u in rmdb.t_users
where u.id == ce.uid && ce.value != x.id
select x).AsEnumerable().Select(x => new ViewModelCheckBox()
{
Value = x.id.ToString(),
Name = x.name,
Checked = false
});
I used the ugly three times from as I'm not that good with creating types for joining.
But that gave wrong result and I realized I had to go for a NOT EXISTS
So I built a new query in T-SQL
This is the SQL query it works!
select distinct * from t_certificates tc
where NOT EXISTS
(
select distinct * from t_users tu, t_user_certificates tuc
WHERE tu.email = 'user#email.com'
and tu.id = tuc.[uid]
and tuc.value = tc.id
)
How would I do that in LINQ?
This is the question, I will award my answer for that!
BUT!
When we are at it... I'm really curious on the answer.. Is it possible to do one LINQ query that return an Ienumerable with both those that EXISTS and NOT EXISTS resulting in an object which will hold DIFFERENT VALUES on the checked property EXISTS -> CHECKED = true NOT EXISTS -> CHECKED = false
This is how I create my object.
.Select(x => new ViewModelCheckBox()
{
Value = x.id.ToString(),
Name = x.name,
Checked = this should be different based on exists or not
});
The LINQ answer should look something like this (untested):
var nocertificates =
from x in rmdb.t_certificates
join tuc in (
from u in rmdb.t_users
join ce in rmdb.t_user_certificates on u.id == ce.uid
select ce.value
) on tuc.value = tc.id into tuc
from y in tuc.DefaultIfEmpty()
where y == null
select x;
This is what I ended up using!
var query = (from tc in rmdb.t_certificates
where !(
from tu in rmdb.t_users
from tuc in rmdb.t_user_certificates
where tu.email == username
&& tu.id == tuc.uid
&& tuc.value == tc.id select tc).AsEnumerable().Any()
select new ViewModelCheckBox()
{ Checked = false,
intconverter = tc.id,
Name = tc.name
});

Distinct works on IQueryable but not List<T>?? Why?

First Table is the View and Second is the result I want
This below query works fine
List<BTWStudents> students = (from V in db.vwStudentCoursesSD
where classIds.Contains(V.Class.Value)
select new BTWStudents
{
StudentId = V.StudentId
Amount= V.PaymentMethod == "Cashier Check" ? V.Amount: "0.00"
}).Distinct().ToList();
But I changed it to List to add string formatting(see below)
List<BTWStudents> students = (from V in db.vwStudentCoursesSD
where classIds.Contains(V.Class.Value)
select new {V}).ToList().Select(x => new BTWStudents
{
StudentId = V.StudentId
Amount= V.PaymentMethod == "Cashier Check" ? String.Format("{0:c}",V.Amount): "0.00"
}).Distinct().ToList();
With this Second Query I get this
Why is distinct not working in the second query?
When working with objects (in your case a wrapped anonymous type because you are using Select new {V} rather than just Select V), Distinct calls the object.Equals when doing the comparison. Internally, this checks the object's hash code. You'll find in this case, the hash code of the two objects is different even though the fields contain the same values. To fix this, you will need to override Equals on the object type or pass a custom IEqualityComparer implementation into the Distinct overload. You should be able to find a number of examples online searching for "Distinct IEqualityComparer".
Try this (moved your distinct to the first query and corrected your bugged if/then/else):
List<BTWStudents> students = (from V in db.vwStudentCoursesSD
where classIds.Contains(V.Class.Value)
select new {V}).Distinct().ToList().Select(x => new BTWStudents
{
classId = V.Class.HasValue ? V.Class.Value : 0,
studentName = V.StudentName,
paymentAmount = V.PaymentMethod == "Cashier Check" ? String.Format("{0:c}",x.V.AmountOwed): "0.00"
}).ToList();
You can get around using Distinct all together if you Group by StudentID
var studentsGroupedByPayment =
(from V in db.vwStudentCoursesSD
where classIds.Contains(V.Class.Value)
group V by V.StudentId into groupedV
select new
{
StudentID = groupedV.Key,
Amount = string.Format("{0:C}",
groupedV.First().PaymentMethod == "Cashier Check" ?
groupedV.First().Amount : 0.0)
}
).ToList();

Error within Where statement in LINQ

For some reason in my where it says that "firstname" does not exist in the Opportunity Entity. But it is set for the SystemUser Entity. Any idea why it is getting confused? Thanks!
var linqQuery = (from r in gServiceContext.CreateQuery("opportunity")
join c in gServiceContext.CreateQuery("account") on ((EntityReference)r["accountid"]).Id equals c["accountid"]
join u in gServiceContext.CreateQuery("systemuser") on ((EntityReference)r["ownerid"]).Id equals u["systemuserid"]
where r["new_leadstatus"].Equals("100000004") && u["lastname"].Equals(rsmLastName) && u["firstname"].Equals(rsmFirstName)
select new
{
AccountId = !r.Contains("accountid") ? string.Empty : r["accountid"],
Account = !r.Contains("name") ? string.Empty : r["name"]
});
Make sure you put each where clause in its own line per Microsoft guidelines.
The where clause applies a filter to the results, often using a
Boolean expression. The filter specifies which elements to exclude
from the source sequence. Each where clause can only contain
conditions against a single entity type. A composite condition
involving multiple entities is not valid. Instead, each entity should
be filtered in separate where clauses.
var linqQuery = from r in gServiceContext.CreateQuery("opportunity")
join c in gServiceContext.CreateQuery("account") on ((EntityReference)r["accountid"]).Id equals c["accountid"]
join u in gServiceContext.CreateQuery("systemuser") on ((EntityReference)r["ownerid"]).Id equals u["systemuserid"]
where r["new_leadstatus"].Equals("100000004")
where u["lastname"].Equals(rsmLastName) && u["firstname"].Equals(rsmFirstName)
select new
{
AccountId = !r.Contains("accountid") ? string.Empty : r["accountid"],
Account = !r.Contains("name") ? string.Empty : r["name"]
};
You define your reference to the Opportunity entity as 'r' but are trying to read firstname from 'u'
from r in gServiceContext.CreateQuery("opportunity")
u["firstname"]
Change the end of your where to
r["firstname"].Equals(rsmFirstName)

LINQ: Self join query, how to accomplish this?

Can anyone help?
I have 1 class, basically it holds Members and within that class is a List.
The members i have in a List also... So basically it goes like this,
I have 2 members and each member has a number of sessions.
I wish to only return each member with 1 Session.
I have done a LINQ query, but of course it doesn't work...
I think i need to do a self join, any ideas?
Basically my error is m doesn't exist in my subquery self join.
var sessions =
from m in this.members
join s in
(
from se in m.Sessions
group se by se.Name into g
select new {Name = g.Key, SessioEndTime = g.Max(a=>a.SessioEndTime)}
)
on m.Name equals s.Name
select new { MemberName = m.Name, SessionTime = s.SessioEndTime}
I would appreciate any feedback anyone has.
Thanks in advance.
EDIT
Ok i managed to do it like the following, but is this the best way?
var sessions =
from m in this.members
let sn = m.Sessions.OrderByDescending(a => a.SessionEndTime).FirstOrDefault()
select new { MemberName = m.Name, SessionTime = sn.SessioEndTime}
This way sn contains 1 record, but i have access to all the properties...
But is this the best way to do using a LET?
Thanks.
Unless I am missing something you need this, no?
var sessions =
from m in members
select new {
MemberName = m.Name,
SessionTime = m.Sessions.Max(s => s.SessioEndTime)
};
You have to change the way you think about LINQ queries, think more from object point rather than from SQL implementation point. What is it that I need? I need all members, each with its latest session end time, then act on that.
EDIT:
The let option you used is ok, just keep something in mind FirstOrDefault will return null if member has an empty list of Sessions, and then sn.SessionEndTime hits null reference. If on the other hand you are certain that every member has at least one session use First instead or aggregate.
Also don't use FirstOrDefault() in the let, it kind of messes up the LINQ and prevents it from tying it to the master (causing a separate SQL query for each master to detect missing subsets), so usable queries with let are:
from m in Members
let sn = m.Sessions.Max(s => s.SessioEndTime)
select new { MemberName = m.Name, SessionTime = sn};
from m in Members
let sn = m.Sessions.OrderByDescending(a => a.SessioEndTime).First()
select new { MemberName = m.Name, SessionTime = sn.SessioEndTime};
As for ordering vs Max aggregation, both queries will generate a subquery:
-- MAX
SELECT [t0].[Name] AS [MemberName], (
SELECT MAX([t1].[SessioEndTime])
FROM [Session] AS [t1]
WHERE [t1].[memberId] = [t0].[id]
) AS [SessionTime]
FROM [Member] AS [t0]
GO
-- ordering
SELECT [t0].[Name] AS [MemberName], (
SELECT [t2].[SessioEndTime]
FROM (
SELECT TOP (1) [t1].[SessioEndTime]
FROM [Session] AS [t1]
WHERE [t1].[memberId] = [t0].[id]
ORDER BY [t1].[SessioEndTime] DESC
) AS [t2]
) AS [SessionTime]
FROM [Member] AS [t0]
With a descending index on SessioEndTime the ordering script is about twice slower (you can get execution plans for these to check for yourself), without the index its about 5times slower.

Linq - How to query specific columns and return a lists

I am trying to write a linq query that will only return certain columns from my entity object into a list object.
Below is my code which produces an error(can't implicitly convert a generic list of anonymous types to a generic list of type TBLPROMOTION):
IQueryable<TBLPROMOTION> matches = webStoreContext.TBLPROMOTION.Include("TBLSTORE").Include("LKPROMOTIONTYPE");
List<TBLPROMOTION> promotionInfo = null;
promotionInfo = (from p in matches
orderby p.PROMOTION_NM descending
select new { p.EFFECTIVE_DT, p.EXPIRE_DT, p.IS_ACTIVE,
p.PROMOTION_DESC, p.PROMOTION_ID, p.PROMOTION_NM }).ToList();
What would be the best way to accomplish this. I do not want to do a "select p" in this case and return all the columns associated with the query.
thanks in advance,
Billy
Can't you do var promotionInfo = () and get a list of anonymous types?
Okay, basically you can not cast an Anonymous type to a known type like TBLPROMOTION.
ofcourse, you can say var promotionInfo = and then get an IEnumerable<{Anonymoustype}> and use that to do, what you were wanting to do with promotionInfo.
Also, personally I prefer the Fluent version of a linq query, easy on the eyes, good programming diet, at least for me :)
var promotionInfo = matches
.OrderByDescending( p => p.PROMOTION_NM)
.Select( p => new { p.EFFECTIVE_DT,
p.EXPIRE_DT,
p.IS_ACTIVE,
p.PROMOTION_DESC,
p.PROMOTION_ID,
p.PROMOTION_NM})
.ToList();
If you're moving from a L2E query to a Type already defined, you may need a step between. I haven't tried to compile this but something like:
List<TBLPROMOTION> promotions = new List<TBLPROMOTION>();
var results = from p in matches
orderby p.PROMOTION_NM descending
select new
{
p.EFFECTIVE_DT,
p.EXPIRE_DT,
p.IS_ACTIVE,
p.PROMOTION_DESC,
p.PROMOTION_ID,
p.PROMOTION_NM
};
foreach (var v in results)
{
promotions.Add(new TBLPROMOTION(v.EFFECTIVE_DT, v.EXPIRE_DT, v.IS_ACTIVE,
v.PROMOTION_DESC, v.PROMOTION_ID, v.PROMOTION_NM));
}
Based on the comment below, you might try something like:
foreach(var v in results)
{
TBLPROMOTION temp = new TBLPROMOTION();
temp.EFFECTIVE_DT = v.EFFECTIVE_DT;
temp.EXPIRE_DT = v.EXPIRE_DT;
temp.IS_ACTIVE = v.IS_ACTIVE
// Assign Other Properties
promotions.Add(temp);
}
.......
Sorry: Just read the addition to the top.
Are you sure that none of the fields you're leaving out (instead of saying "select p") are required for a TBLPROMOTION object? Also, sense your TBLPROMOTION object is going to have properties (and therefore memory allocated) for those skipped fields, why not just use an annonymous type or set up a helper class that contains only your needed properties?
#Billy, following code worked for me.
List<TBLPROMOTION> promotionInfo =
(from p in matches
orderby p.PROMOTION_NM descending
select new TBLPROMOTION(p.EFFECTIVE_DT, p.EXPIRE_DT, p.IS_ACTIVE,
p.PROMOTION_DESC, p.PROMOTION_ID, p.PROMOTION_NM)
).ToList();
did you try
select new TBLPROMOTION {.....
instead of
select new {.....
List<TBLPROMOTION> promotionInfo = null;
promotionInfo = (from p in matches
orderby p.PROMOTION_NM descending
select new TBLPROMOTION { COL1 = p.EFFECTIVE_DT, COL2 = p.EXPIRE_DT, COL3 = p.IS_ACTIVE... }).ToList();
Where COL1, COL2, ... are the names of the properties on TBLPROMOTION you wish you populate.
If you want a subset of the table you have 2 options:
#Fredou mentioned select new TBLPROMOTION{...}
other way is to create a custom DTO which has the exact properties & select them instead like:
List promotionInfo = ...
select new TBLPROMOTION_DTO{
Effective_dt = ...
}
HTH

Resources