Switch gears from TSQL to LINQ - c#

I am trying to take the TSQL below and convert it into LINQ. I'm obviously not very good at this and not sure how to go about doing a join in Linq. My confusion goes a little beyond just the simple expression. In my basic uses my result set is a class that of course represents a table row...but a join would not have this one to one ratio so do I have to create a custom result set?
TSQL:
SELECT
SimEA.*,
SimE.*
FROM
dbo.SSimEmailsAdressees SimEA
JOIN dbo.SSimEmails SimE ON
SimEA.EmailID = SimE.EmailMsgID
WHERE
SimEA.UserId = var
The closest I have come:
this.GetAll<SSimEmails>()
.Where(e => e.SSimEmailsAdressees.Any(p => p.UserId.ToString() == usrID));
Which of course return an object that is a mimic of the single table being queried. So I need help getting the join added and I'm guessing I'll have to create a return object something like this?
this.GetAll<MyJoinResultsObject>......

I think that you should write something like:
var q =
from SimEA in SSimEmailsAdressees
where SimEA.UserId = usrID
join SimE in SSimEmails on SimEA.EmailID equals SimE.EmailMsgID
into joinSimE
from SimE in joinSimE.DefaultIfEmpty()
select new { EmailID = SimEA.EMailID, UserId = SimEA.UserId, OtherField = SimE.OtherField };

var result = from ea in SimEA
join e in SimE
on ea.EmailID equals e.EmailMsgID
where ea.UserId = userId
select new { properties you want here or new object based on properties}

Related

How do I group one to many in a nested fashion with linq to entities?

I have three tables, Chart, ChartQuestion, ChartAnswer
A Chart has many ChartQuestions, a ChartQuestion has many ChartAnswers.
I'd like to do a linq query that gives me an object containing all of this data, so it'd be a ChartObject containing List<ChartQuestion> and each ChartQuestion contains a List<ChartAnswer>
I started with this:
(from chart in db.Chart
join chartQuestion in db.chartQuestion on chart.ChartId equals chartQuestion.ChartId into chartQuestions)
This seems to be the first step. However I want to include the ChartAnswers now, so I have to do another join to pull back the ChartAnswers but I don't know how to do this.
I can't do a join, and while I can do a from, I am not sure of the exact syntax.
(from chart in db.Chart
join chartQuestion in db.chartQuestion on chart.ChartId equals chartQuestion.ChartId into chartQuestions
from chartQuestionsSelection in chartQuestions
join chartAnswer in context.ChartAnswers on chartQuestions.ChartAnswerId equals chartAnswer.ChartAnswerId into chartAnswers // This is wrong
)
With that code above you end up as chartAnswers being separate to the chartQuestions rather than belonging to them, so I don't think it is correct.
Any idea?
joining a table destructors it i.e. you now have the row as a variable if you need it in a nested fashion then select in like this
(from chart in db.Chart
select new { //can also be your own class/record, perhaps a DTO
chart.Id,
chart.Name,
questions = (from chartQuestion in db.chartQuestion
where chart.ChartId == chartQuestion.ChartId
select new { //perhaps a dto
chartQuestion.Id,
chartQuestion.Question,
Answers =
(from chartAnswer in context.ChartAnswers
where chartAnswer.ChartAnswerId == chartQuestion.ChartAnswerId
select chartAnswer).ToList() //this is translated and not evaluated
}).ToList() //this is translated not evaluated
}).ToListAsync(cancellationToken) //this will evaluate the expression
If you need it by joins then you can group join it like this:
from m in _context.Chart
join d in _context.ChartQuestions
on m.ID equals d.ID into mdJoin
select new
{
chartId = m.ID,
chartName = "m.name",
quess = from d in mdJoin
join dd in _context.ChartAnswer
on d.Iddomain equals dd.DomainId into anJoin
select new
{
quesId = d.ID,
quesName = d.Question,
anss = anJoin
}
}
A better way: If you edit your DbConfigurations to include navigation properties of each then the code will become way simpler.
example:
db.Chart
.Include(x => x.chartQuestions)
.ThenInclude(x => x.chartAnswers)
You can search more about how to do navigation properties in EFCore, but ofcourse if the code base is large then this might not be feasible for you.
Try following :
(from chart in db.Chart
join chartQuestion in db.chartQuestion on chart.ChartId equals chartQuestion.ChartId
join chartAnswer in context.ChartAnswers on chartAnswer.ChartAnswerId equals chartQuestion.ChartAnswerId
)

LINQ how to translate subquery in FROM clause

Newb to C#.Net / LINQ
I have to convert some dynamic stored procs to LINQ. I'm new to LINQ, and looking for an example to follow. I have something like the following:
sql1 VARCHAR2(32000) := ' SELECT a,b,c FROM ( ';
from1 VARCHAR2(32000) := ' SELECT x,y,z FROM t1, t2,
(SELECT xx FROM aTable WHERE foo = 'bar' )
WHERE x=1
AND y=2';
Anyway, hope this gets the example across.
I was hoping to do something like:
var subSelect1 = (from val1 in aTable
where val1.foo = "bar"
select new {
val1.foobar
}).AsEnumerable();
var mainSelect = (from <how do I use the subSelect1 as a virtual table here?>
Is this possible in LINQ?
The actual query is quite long and complex...having several subqueries in the FROM clause of the main select, and some of the subqueries in the FROM have themselves nested subqueries in -their- FROM clause.
What may help is going through a couple sample linq queries and look at the results. For example, the following code will create an IEnumerable of val1's.
var subSelect1 = (from val1 in aTable
where val1.foo = "bar"
);
Note the above is equivalent to the below.
var subSelect1 = (from val1 in aTable
where val1.foo = "bar"
select val1 /* this select statement is implied in the above */
);
Adding the select new {val1.foobar} after the where clause creates an IEnumerable of an anonymous type, with one property named foobar. This means that you'll only be able to join against the one property foobar.
var subSelect1 = (from val1 in aTable
where val1.foo == "bar"
select new {val1.foobar}
);
var mainSelect = (from f in subSelect1
where f.foobar == "test")
By leaving out the select new, you'll have access to all the fields in val1.
var subSelect1 = (from val1 in aTable
where val1.foo == "bar"
);
var mainSelect = (from v in subSelect1
where v.foobar == "test"
and v.bar == "status"
)
I am not very clear regarding your exact requirement, but my understanding is you need a chained Linq Query such that the parent data can be filtered using the Subquery result. Also the Fluent syntax is a set of extension methods on IEnumerable<T>, therefore a DataTable needs AsEnumerable() to be called so that operations can be done on IEnumerable<DataRow> and later on CopyToDataTable in the System.Data.DataSetExtensions can be called for re-conversion. Also since we are dealing with DataRows, therefore value access need indexer, like dataRow["ColumnName"] or dataRow[ColumnIndex]
// dr is the DataRow type (fetching all the Datarows, instead of specific Column like foobar)
Creating Subselect1 IEnumerable<DataRow>
var subSelect1 = aTable.AsEnumerable()
.Where(dr => dr["foo"] == "bar")
var mainSelect = (from <how do I use the subSelect1 as a virtual table here?
This shall be simple, depending on exactly what you need to do I assume, you need to match the DataRows that exist in subSelect1, then so something like:
var mainSelect = MainDataTable.AsEnumerable()
.Where(dr => subSelect1.Contains(dr))
var mainSelectDataTable = mainSelect.CopyToDataTable();
Idea remains, its very simple to create complex chained queries in Linq, provided you know exactly what you need, which is not very clear from the question

Joining Two Tables based upon a Key using LINQ to SQL

I've got Two tables
Attribute(AID, Name, Description)
AttributeVal(AID,Value)
Now, Using LINQ I need to get the Name, Description and Value by joining these two tables. So, far I got here..
var displayAttributeMap = dctx.Attributes.Join(dctx.AttributeDisplayNames, a => a.AttributeID, adn => adn.AttributeID,
(a, adn) => new
{
AttributeName = a.Name,
AttributeDispName = adn.DisplayName
}
).ToDictionary(a => a.AttributeName, a => a.AttributeDispName);
But here I don't know where to insert a condition on the foreign key, in my case it is Attribute ID. Am I missing something here or should I use LINQ directly?
From what I gather, you need the value AND the display name of the attribute put into a dictionary.
All you need to do is add another join to your current query and change your select and ToDictionary around a bit. I find using the query syntax easier to read and use when dealing with joins.
(from attr in dctx.Attributes
join attrDisplayName in dctx.AttributeDisplayNames on attr.AttributeID equals attrDisplayName.AttributeID
join attrVal in dctx.AttributeVal on attr.AttributeID equals attrVal.AttributeID
select new
{
AttributeName = attr.Name,
AttributeDispName = attrDisplayName.DisplayName,
AttributeID = attr.AttributeID,
AttributeValue = attrVal.Value
}).ToDictionary(key => key.AttributeID, (value) => { return new { DisplayName = value.AttributeDispName, Value = value.AttributeValue };})
I haven't tested it but LinqPad is happy with the syntax, so I think it should work.

SQL Query to LINQ

I want to convert this query to LINQ to use with Entity Framework 4.
Select *,
(select SUM(Of_Orders.Contribution) from Of_Orders
where Of_Orders.CauseID = Of_Causes.CauseID) AS Earned
FROM Of_Causes
Can anyone help me to do this.
Thanks in Advance
It cools like the CauseID field represents a foreign key? If it does then you can map an association in your entity model, so that cause.Orders is a property you can access. Side note, you can also rename the entities/properties, they don't have to match table names so you could get rid of the ugly underscores! That would then look like this:
var result = from c in context.Of_Causes
select new {cause, cause.Orders.Sum(o => o.Contribution}
You'd get a few benefits from doing that (if you can), like a cleaner model, and more efficient SQL queries being generated.
If you can't use a foreign key, I'd join the tables manually which again should help performance.
I believe that would look like this but my translation from VB to C# may be dodgy, here's the C#:
var context = new ModelContainer();
var result = from c in context.Of_Cause
join o in context.Of_Orders on c.Id equals o.CauseID into g
select new {Cause = c, Total = g.Sum(o => o.Contribution)};
And here's the VB original in case my translation is off!
Dim result = From cause As Of_Cause In context.Of_Cause
Group Join order As Of_Orders In context.Of_Orders On order.CauseID Equals cause.Id Into total = Sum(order.Contribution)
Select New With {.Cause = cause, .Total = total}
That would be something similar to:
from cause in context.Of_Causes
select new {
cause,
Earned = context.Of_Orders.Where(o => o.CauseID == cause.CauseID).Sum(o => o.Contribution)
};
I've made some assumptions about the types involved, but that should be easy for you to work out.

How to do joins in LINQ on multiple fields in single join

I need to do a LINQ2DataSet query that does a join on more than one field (as
var result = from x in entity
join y in entity2
on x.field1 = y.field1
and
x.field2 = y.field2
I have yet found a suitable solution (I can add the extra constraints to a where clause, but this is far from a suitable solution, or use this solution, but that assumes an equijoin).
Is it possible in LINQ to join on multiple fields in a single join?
EDIT
var result = from x in entity
join y in entity2
on new { x.field1, x.field2 } equals new { y.field1, y.field2 }
is the solution I referenced as assuming an equijoin above.
Further EDIT
To answer criticism that my original example was an equijoin, I do acknowledge that, My current requirement is for an equijoin and I have already employed the solution I referenced above.
I am, however, trying to understand what possibilities and best practices I have / should employ with LINQ. I am going to need to do a Date range query join with a table ID soon, and was just pre-empting that issue, It looks like I shall have to add the date range in the where clause.
Thanks, as always, for all suggestions and comments given
var result = from x in entity
join y in entity2 on new { x.field1, x.field2 } equals new { y.field1, y.field2 }
var result = from x in entity1
join y in entity2
on new { X1= x.field1, X2= x.field2 } equals new { X1=y.field1, X2= y.field2 }
You need to do this, if the column names are different in two entities.
The solution with the anonymous type should work fine. LINQ can only represent equijoins (with join clauses, anyway), and indeed that's what you've said you want to express anyway based on your original query.
If you don't like the version with the anonymous type for some specific reason, you should explain that reason.
If you want to do something other than what you originally asked for, please give an example of what you really want to do.
EDIT: Responding to the edit in the question: yes, to do a "date range" join, you need to use a where clause instead. They're semantically equivalent really, so it's just a matter of the optimisations available. Equijoins provide simple optimisation (in LINQ to Objects, which includes LINQ to DataSets) by creating a lookup based on the inner sequence - think of it as a hashtable from key to a sequence of entries matching that key.
Doing that with date ranges is somewhat harder. However, depending on exactly what you mean by a "date range join" you may be able to do something similar - if you're planning on creating "bands" of dates (e.g. one per year) such that two entries which occur in the same year (but not on the same date) should match, then you can do it just by using that band as the key. If it's more complicated, e.g. one side of the join provides a range, and the other side of the join provides a single date, matching if it falls within that range, that would be better handled with a where clause (after a second from clause) IMO. You could do some particularly funky magic by ordering one side or the other to find matches more efficiently, but that would be a lot of work - I'd only do that kind of thing after checking whether performance is an issue.
Just to complete this with an equivalent method chain syntax:
entity.Join(entity2, x => new {x.Field1, x.Field2},
y => new {y.Field1, y.Field2}, (x, y) => x);
While the last argument (x, y) => x is what you select (in the above case we select x).
I think a more readable and flexible option is to use Where function:
var result = from x in entity1
from y in entity2
.Where(y => y.field1 == x.field1 && y.field2 == x.field2)
This also allows to easily change from inner join to left join by appending .DefaultIfEmpty().
var result = from x in entity
join y in entity2
on new { X1= x.field1, X2= x.field2 } equals new { X1=y.field1, X2= y.field2 }
select new
{
/// Columns
};
you could do something like (below)
var query = from p in context.T1
join q in context.T2
on
new { p.Col1, p.Col2 }
equals
new { q.Col1, q.Col2 }
select new {p...., q......};
Using the join operator you can only perform equijoins. Other types of joins can be constructed using other operators. I'm not sure whether the exact join you are trying to do would be easier using these methods or by changing the where clause. Documentation on the join clause can be found here. MSDN has an article on join operations with multiple links to examples of other joins, as well.
If the field name are different in entities
var result = from x in entity
join y in entity2 on
new {
field1= x.field1,
field2 = x.field2
}
equals
new {
field1= y.field1,
field2= y.myfield
}
select new {x,y});
As a full method chain that would look like this:
lista.SelectMany(a => listb.Where(xi => b.Id == a.Id && b.Total != a.Total),
(a, b) => new ResultItem
{
Id = a.Id,
ATotal = a.Total,
BTotal = b.Total
}).ToList();
I used tuples to do that, this is an example for two columns :
var list= list1.Join(list2,
e1 => (e1.val1,e1.val2),
e2 => (e2.val1,e2.val2),
(e1, e2) => e1).ToList();
from d in db.CourseDispatches
join du in db.DispatchUsers on d.id equals du.dispatch_id
join u in db.Users on du.user_id equals u.id
join fr in db.Forumreports on (d.course_id + '_' + du.user_id) equals (fr.course_id + '_'+ fr.uid)
this works for me
Declare a Class(Type) to hold the elements you want to join. In the below example declare JoinElement
public class **JoinElement**
{
public int? Id { get; set; }
public string Name { get; set; }
}
results = from course in courseQueryable.AsQueryable()
join agency in agencyQueryable.AsQueryable()
on new **JoinElement**() { Id = course.CourseAgencyId, Name = course.CourseDeveloper }
equals new **JoinElement**() { Id = agency.CourseAgencyId, Name = "D" } into temp1

Categories