These are my two tables:
publicParking(publicParkingID, address, latitude, longtitude, status,
PricePerHour, maxSpaces, occupiedSpaces, freeSpaces, isOrdered)
and
parkingLot(parkingLotID, address, latitude, longtitude, status,
PricePerHour, maxSpaces, occupiedSpaces, freeSpaces, isOrdered)
All of the columns are the same except the ID.
I need to write query in LINQ that will return a table ordered by price with all the available parkings (publicParking / parkingLot) - with status==true.
The table should look like this:
ID address latitude longitude status
Should I do a union, or should I change the table so the first column will call just ID? (instead of publicParkingID and parkingLotID)
I've tried this code but it does not work
var union =
(from lot in parkingLots
where lot.status == true
select lot).Union( from pub in publicParkings
where pub.status==true
select pub);
It give this error :
I am working with LINQPad5 and with code editor of tutorialsteacher. Are there are other options?
To use Union both result sequences must contain the same types. In your example the outer query contains parkingLot and the inner publicParking.
It could be solved using anonymous types:
var union =
(from lot in parkingLots
where lot.status == true
orderby lot.PricePerHour // don't forget ordering
select new {
ID = lot.parkingLotID,
lot.address, lot.latitude, lot.longitude, lot.status})
.Union(from pub in publicParkings
where pub.status==true
orderby pub.PricePerHour // don't forget ordering
select new {
ID = pub.publicParkingID,
pub.address, pub.latitude, pub.longitude, pub.status});
But maybe better for further data handling would be a custom class:
public class ParkingData
{
public int ID {get; set;}
public string Address {get; set;}
public double Latitude {get; set;}
public string Longitude {get; set;}
public bool Status {get; set;}
}
and query like that:
var union =
(from lot in parkingLots
where lot.status == true
orderby lot.PricePerHour // don't forget ordering
select new ParkingData {
ID = lot.parkingLotID,
Address = lot.address,
Latitude = lot.latitude,
Longitude = lot.longitude,
Status = lot.status})
.Union(from pub in publicParkings
where pub.status==true
orderby pub.PricePerHour // don't forget ordering
select new {
select new ParkingData {
ID = pub.publicParkingID,
Address = pub.address,
Latitude = pub.latitude,
Longitude = pub.longitude,
Status = pub.status});
Related
I am using ef-core 2.1, I have the following simplified entities where one Account maps to zero or more Attribute objects:
public class Account
{
public int Id { get; set; }
public int LongId { get; set; }
public List<Attribute> Attributes { get; set; }
}
public class Attribute
{
public int Id { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public Account Account { get; set; }
}
I have an initial collection of strings that resemble an Attribute.Value for a given fixed Attribute.Name, I want to find a second associated Attribute object from the same parent Account and obtain its Attribute.Value.
I want to left join the ef entities against the initial string collection so I can easily infer:
Whether no corresponding Account exists or an Account exists without the related Attribute objects (both equate to the same use case).
If an Account exists and it contains all the required Attribute objects, I want to obtain the value of the secondary Attribute.
Without LINQ and ef, I run the following SQL query which ignores the parent Account and produces the result set I want:
CREATE TABLE #Temp
(
id nvarchar(20) not null
);
INSERT INTO #Temp (id) VALUES ('cejawq'), ('issokq'), ('cqlpjq'), ('mbgzvi'), ('wqwlff'), ('iedifh');
SELECT t.[Id], attr2.[Value]
FROM #Temp t
LEFT OUTER JOIN [dbo].[Attributes] attr1
ON t.[Id]=attr1.[Value]
AND attr1.[Name]='uid'
LEFT OUTER JOIN [dbo].[Attributes] attr2
ON attr1.[AccountId]=attr2.[AccountId]
AND attr2.[Name]='objType';
I get the following result set:
id|objType
-----------
cejawq|ext
issokq|ext
cqlpjq|int
mbgzvi|int
wqwlff|ext
iedifh|null
I am struggling with mapping this to efficient LINQ such that the SQL generated produces the result set remotely and ships back data that I can project to an equivalent anonymous type. Do I need to care about the parent objects in the LINQ case? I don't have an index on the Attribute.Value column.
The Attributes table contains the following data:
Id|Name |Value |AccountId
1 |uid |cejawq|1
2 |objType|ext |1
3 |uid |issokq|2
4 |objType|ext |2
5 |uid |cqlpjq|3
6 |objType|int |3
7 |uid |mbgzvi|4
8 |objType|int |4
9 |uid |wqwlff|5
10|objType|ext |5
Since the EF Core does not support joins with in memory sequences (yet), you can split the query in two parts - one which takes the data server side ([Attributes to [Attributes join) using in memory collection as filter (SQL IN through LINQ Contains method), and second which performs left join in memory with the result of the db query:
DbContext db = ...;
var uids = new [] { "cejawq", "issokq", "cqlpjq", "mbgzvi", "wqwlff", "iedifh" };
var dbQuery =
from attr1 in db.Set<Attribute>()
where attr1.Name == "uid" && uids.Contains(attr1.Value)
join attr2 in db.Set<Attribute>()
on new { AccountId = attr1.Account.Id, Name = "objType" }
equals new { AccountId = attr2.Account.Id, attr2.Name }
into attr2Group from attr2 in attr2Group.DefaultIfEmpty() // left outer join
select new { uid = attr1.Value, objType = attr2.Value };
var query =
from uid in uids
join dbResult in dbQuery on uid equals dbResult.uid
into dbResultGroup from dbResult in dbResultGroup.DefaultIfEmpty() // left outer join
select new { uid, dbResult?.objType };
var result = query.ToList();
It translates to a single db query like this:
SELECT [attr1].[Value] AS [uid], [attr2].[Value] AS [objType]
FROM [Attributes] AS [attr1]
LEFT JOIN [Attributes] AS [attr2] ON ([attr1].[AccountId] = [attr2].[AccountId]) AND (N'objType' = [attr2].[Name])
WHERE ([attr1].[Name] = N'uid') AND [attr1].[Value] IN (N'cejawq', N'issokq', N'cqlpjq', N'mbgzvi', N'wqwlff', N'iedifh')
I am looking for a LINQ to use with my datatable and display all the duplicate rows based on certain columns in windows form datagrid view.
The LINQ should give a result similar to the plain old below give SQL.
SELECT *
FROM Table1 t
JOIN ( SELECT Taskid, Studentid, DateChangeid
FROM Table1
GROUP BY Taskid, studentid, datechangeid
HAVING COUNT(*) > 1) temp
ON t.taskid = temp.taskid AND t.studentid= temp.studentid AND t.datechangeid= temp.datechangeid
This should do what you want:
var result =
t.GroupBy(g => new {TaskId = Taskid, StudentId = studentid, DatechangeId = datechangeid})
.Where(g => g.Count > 1)
.ToList();
Now you're joining Table1 on Table1 which isn't needed, just do the filtering on Table1 only.
Now the result will be of type List<IGrouping<'a,Table1>> though because of the anonymous keyselector, you can also define TaskId , StudentId and DateChangeID in a class to get rid of that. For example:
public class Table1GroupKey
{
public int TaskId {get; set;}
public int StudentId {get; set;}
public int DateChangeId {get; set;}
}
Then you can use:
GroupBy(g => new Table1GroupKey { ... })
And your result will be List<IGrouping<Table1GroupKey,Table1>>.
I managed it by writing two linq as given below.
var RepeatedValues = from d in DataTableitems.AsEnumerable()
group d by d.Field<string>("MobileNo") into itemGroup
where itemGroup.Count() > 1
select new { name = itemGroup.Key };
var RepeatedInRows= from d in DataTableitems.AsEnumerable()
join c in RepeatedValues.AsEnumerable() on d.Field<string>
("MobileNo") equals c.name
select d;
Question:
I'm trying to use PetaPoco to join more than four tables to populate an object of type A with five members of type B (very similiar to this question: https://stackoverflow.com/a/11275334/296296). From what I've read it would be possible to use this syntax:
var result = db.Query<Investment>(new System.Type[] { typeof(Investment), typeof(Person), typeof(Person), typeof(Person), typeof(Person), typeof(Person) }, null, sql, null).FirstOrDefault();
Where the sql is:
SELECT Investment.*, p1.*, p2.*, p3.*, p4.*, p5.* FROM Investment
INNER JOIN People p1 ON Investment.OwnerID = p1.Id
INNER JOIN People p2 ON Investment.ITOwnerID = p2.Id
INNER JOIN People p3 ON Investment.InformationOwnerId = p3.Id
INNER JOIN People p4 ON Investment.MaintenanceLeaderId = p4.Id
INNER JOIN People p5 ON Investment.MaintenanceLeaderITId = p5.Id
WHERE (Investment.Id = #0)
But it just gives me the following error:
Can't auto join Person as Investment has more than one property of type Person
Anyone who had the same problem or could help in any way?
Background:
I have the following (simplified) database tables:
Investment
--------------
Id
Name
OwnerId
ITOwnerId
InformationOwnerId
MaintenanceLeaderId
MaintenanceLeaderITId
People
--------------
Id
Name
The classes I would like to map these database tables to are:
Public class Investment {
public int Id
public string Name
public Person Owner
public Person ITOwner
public Person InformationOwner
public Person MaintenanceLeader
public Person MaintenanceLeaderIT
}
Public class Person {
public int Id
public string Name
}
In order to do so, I need to join the People table for every Person-type in the Investment class and map them to the corresponding property as instances of the type Person.
The only way you could possibly do this is create your own callback (instead of letting it fall back to the self discovering callback thats currently being invoked) where you wire up each Person object on the Investment object.
Take a look at http://www.toptensoftware.com/Articles/115/PetaPoco-Mapping-One-to-Many-and-Many-to-One-Relationships
why can't you do this :
/////SQL CODE for testing the selects
DECLARE #People TABLE (Id INT, Name VARCHAR(50))
INSERT INTO #People (Id,Name)
SELECT 1,' John Smith' UNION ALL
SELECT 2,'Albert Lee' UNION ALL
SELECT 3,'Christina Wetherbe' UNION ALL
SELECT 4,'Alice Cany' UNION ALL
SELECT 5,'Jim Blabery' UNION ALL
SELECT 6,'Octaviose Mayflower' UNION ALL
SELECT 7,'Sandra Lee M' UNION ALL
SELECT 8,'Some test user' UNION ALL
SELECT 9,'Some test user 2' UNION ALL
SELECT 10,'Some test user 3' UNION ALL
SELECT 11,'Some test user 4'
DECLARE #Investment TABLE (
Id INT,
Name VARCHAR(50),
OwnerId INT,
ITOwnerId INT,
InformationOwnerId INT,
MaintenanceLeaderId INT,
MaintenanceLeaderITId INT
)
INSERT INTO #Investment(Id,Name,OwnerId,ITOwnerId,InformationOwnerId,MaintenanceLeaderId,MaintenanceLeaderITId)
SELECT 1,'INVESTMENT 1',1,2,1,3,4 UNION ALL
SELECT 2,'INVESTMENT 2',1,3,2,3,2 UNION ALL
SELECT 3,'INVESTMENT 3',3,1,3,3,4 UNION ALL
SELECT 4,'INVESTMENT 4',5,4,4,2,3 UNION ALL
SELECT 5,'INVESTMENT 5',6,5,5,7,6 UNION ALL
SELECT 6,'INVESTMENT 6',8,6,6,7,8 UNION ALL
SELECT 7,'INVESTMENT 7',9,8,7,4,5 UNION ALL
SELECT 8,'INVESTMENT 8',11,8,8,6,11 UNION ALL
SELECT 9,'INVESTMENT 9',10,9,9,10,9
--SELECT * FROM #People
--SELECT * FROM #Investment
-- THIS IS YOUR SELECT STATEMENT to be uses in PetaPoco call
SELECT unpv.Id,unpv.Name, unpv.INVTYPE,unpv.PersonId,p.Name FROM #Investment
UNPIVOT(PersonId for INVTYPE in (OwnerId,ITOwnerId,InformationOwnerId,MaintenanceLeaderId,MaintenanceLeaderITId))unpv
join #People p on unpv.PersonId = p.Id
order by INVTYPE, PersonId
Then C# code as
1 - Extend your Investment POCO to have 2 more columns, INVTYPE and PersonId. Just create new object in the same name-space. Like so:
public partial class Investment
{
[ResultColumn]
public string INVTYPE { set; get; }
[ResultColumn]
public int PersonId { set; get; }
}
2 - create viewclass InvestmentView (you can use your Investment class for that, just rename it)
var myInvestmentView = new InvestmentView
{
Id = result.Id,
Name = result.Name,
Owner = new Person{ Id = result.firstOrDefault(o => o.INVTYPE.Equals("OwnerId")).PersonId, Name = result.firstOrDefault(o=> o.INVTYPE.Equals("OwnerId")).PersonName},
ITOwner = new Person{ Id = result.firstOrDefault(o => o.INVTYPE.Equals("ITOwnerId")).PersonId, Name = result.firstOrDefault(o=> o.INVTYPE.Equals("ITOwnerId")).PersonName},
InformationOwner = new Person{ Id = result.firstOrDefault(o => o.INVTYPE.Equals("InformationOwnerId")).PersonId, Name = result.firstOrDefault(o=> o.INVTYPE.Equals("InformationOwnerId")).PersonName},
MaintenanceLeader = new Person{ Id = result.firstOrDefault(o => o.INVTYPE.Equals("MaintenanceLeaderId")).PersonId, Name = result.firstOrDefault(o=> o.INVTYPE.Equals("MaintenanceLeaderId")).PersonName},
MaintenanceLeaderIT = new Person{ Id = result.firstOrDefault(o => o.INVTYPE.Equals("MaintenanceLeaderITId")).PersonId, Name = result.firstOrDefault(o=> o.INVTYPE.Equals("MaintenanceLeaderITId")).PersonName}
}
3 - populate the class with data from the list returned
using (var data = new Database(Config.MainDbConnectionName))
{
var result = data.Fetch<Investment,People>(
Sql.Builder
.Append("SELECT unpv.Id,unpv.Name, unpv.INVTYPE,unpv.PersonId,p.name as PersonName FROM Investment")
.Append(" UNPIVOT(PersonId for INVTYPE in (OwnerId,ITOwnerId,InformationOwnerId,MaintenanceLeaderId,MaintenanceLeaderITId)) unpv")
.Append(" JOIN People p on unpv.PersonId = p.Id")
.Append(" WHERE (Investment.Id = #0)",InvId)
.Append(" ORDER BY INVTYPE, PersonId")
);
}
this way the only class that will need the special treatment will be Investment class as you would need to process the data backwards from InvestmentView into flat structure of POCO.
I'm having a problem getting some data since I'm just starting to use LINQToEntities, Entity Framework and Lambda Expressions.
Let me explain my case:
I have a database with 4 tables as shown here:
when I generate the model from database in Visual Studio (2010) the result is this:
I searched for some info and turns out that since the table t_user_role only has the ids from its two parent tables, it gets abstracted in the model, and you have to use the navigation properties instead.
I had some problem getting the role info for a user on a given system (as the next function does)
public t_role GetRoleForUser(string userId, string sysId)
{
entities = new secfinEntities(); //context from the model
t_role userRole = entities.t_role.Where(r => r.t_user.Any(u => u.uid == userId) & r.sys_id == sysId).First();
return userRole;
}
Now I have to implement a simple search function that will look users that contain the provided string and return the user's id and name (uid, user_name) and their role's info (role_id, role_name) on a given system (the system info i have beforehand), so basically I wanna turn this next SQL Query into Lambda Expressions (keeping in mind that in the model the table t_user_role has been abstracted)
SELECT U.uid, U.user_name, R.role_id, R.role_name
FROM t_user U
INNER JOIN t_user_role UR ON U.uid = UR.uid
INNER JOIN t_role R ON UR.role_id = R.role_id
WHERE R.sys_id = #p0 -- first parameter
AND U.user_name LIKE '%' + #p1 + '%' -- second parameter
Also, I would like to store the results of that in a List of a type I have defined as follows:
public class UserRole
{
public string UserId { get; set; }
public string UserName { get; set; }
public string RoleId { get; set; }
public string RoleName { get; set; }
public UserRole(string uid, string uname, string rid, string rname)
{
UserId = uid;
UserName = uname;
RoleId = rid;
RoleName = rname;
}
}
So after explaining what I have done and what I'm trying to do first question is: how can that be done?, second: can the same be accomplished through the verbose form instead of Lambda expressions? if yes, how?
Thanks a lot in advance for your time.
This T-SQL:
SELECT U.uid, U.user_name, R.role_id, R.role_name
FROM t_user U
INNER JOIN t_user_role UR ON U.uid = UR.uid
INNER JOIN t_role R ON UR.role_id = R.role_id
WHERE R.sys_id = #p0 -- first parameter
AND U.user_name LIKE '%' + #p1 + '%' -- second parameter
given your model translates to this verbose syntax (including the requirement to use your new model):
var results = (from u in entities.t_user
from r in u.t_role
where r.sys_id == sysIdVariable && u.user_name.Contains(userNameVariable)
select new UserRole(u.uid, u.user_name, r.role_id, r.role_name))
I know you didn't ask for it, but a lambda version might look like:
var results = entities.t_user.Join(entities.t_role,
x => x.t_role_id,
x => x.role_id,
(u, r) => new UserRole(u.uid,
u.user_name,
r.role_id,
r.role_name))
I have the following working TSQL query in ms SQL 2008
SELECT
Date,
COUNT(click) AS clicks,
COUNT(sale) AS sales,
count(lead) as leads
FROM
(
SELECT ClickDate as date ,ID AS click ,CAST(NULL AS int) AS sale , CAST(null as int) as lead
FROM clicks
UNION ALL
SELECT Date,null, ID ,NULL
FROM sales
UNION ALL
SELECT Date,null, NULL ,ID
FROM leads
) t
GROUP BY Date
How would i convert this to LINQ to SQL?
I wrote this LINQ but it doesn't work.
public class mydata
{
public DateTime date { get; set; }
public int? click { get; set; }
public int? sale { get; set; }
public int? lead { get; set; }
}
var clicks = from c in Clicks
select new mydata
{
date = c.ClickDate, click = c.ID, sale = null, lead = null
};
var sales = from s in Sales
select new mydata
{
date = s.Date, click = null, sale = s.ID, lead = null
};
var leads = from l in Leads
select new mydata
{
date = l.Date, click = null, sale = null, lead = l.ID
};
var v = clicks.Concat(sales).Concat(leads);
var res = from x in v
group x by x.date into xg
select new
{
date = xg.Key, clicks = xg.Count(z => z.click != null)
};
}
How do i correct this LINQ query?
Update:
i Modified the LINQ query based on David B recommendation.
i'm still getting the following error:
"All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists."
David's correct about the first two issues. For your final problem (3), Count() does not work like it does in SQL. It expects a predicate that returns a bool. Your using it with ints (i.e. z.click, z.sales, etc.)
The problem is that the anonymous types in the projections are not identical... ID is int in one and Nullable<int> in another.
Instead of using an anonymous type in your projections, use this:
public class ConcatTarget
{
public DateTime TheDate {get;set;}
public int? ID {get;set;}
public string sale {get;set;}
public string lead {get;set;}
}
Even though no instances are actually constructed, LinqToSql uses the class's shape to translate the query.
As for Count, perhaps you meant .Count(x => x.Prop != null) ?
Ok, apparently you've hit upon a buggy translation behavior as described here.
What's happening is the sql translator sees the null assignments, and throws them away. This causes an incorrect number of sql columns to be selected between the sets.
Here's a possible workaround:
int? myNull = null;
var clicks =
from c in Clicks
select new mydata
{
date = c.ClickDate,
click = c.ID,
sale = c.ID + myNull,
lead = myNull + c.ID //note - expressions must be unique
};
The basic idea is to create unique expressions the query translator can't throw away. This is harder than it sounds (above is my ninth attempt).
Here's the other two tables:
var sales = from s in Sales
select new mydata
{
date = s.Date,
click = s.ID + myNull,
sale = s.ID,
lead = myNull + s.ID
};
var leads = from l in Leads
select new mydata
{
date = l.Date,
click = l.ID + myNull,
sale = myNull + l.ID,
lead = l.ID
};
If you had more than 2 columns-to-be-nulled, you could resort to subtraction, division, multiplication, etc.