How to get SQL query into LINQ form in C# code - c#

How can I convert the following SQL queries into LINQ query form in C#, .NET 3.5 code:
1)
select COUNT(distinct Skill_Name)
from Table1
where Department = 'ABC' and Skill_Name is not null
2)
select distinct location, country from Customer where Customer_Code ='1001';

I suspect you want:
var query = from entry in dbContext.Table1
where entry.Department == "ABC" && entry.SkillName != null
select entry.SkillName;
var count = query.Distinct().Count();
Or using extension method syntax, in one go:
var count = dbContext.Table1
.Where(entry => entry.Department == "ABC" &&
entry.SkillName != null)
.Select(entry => entry.SkillName)
.Distinct()
.Count();
As shown by mesiesta, you can combine query expressions with calls not supported within query expressions, but I tend to assign the query expression to an intermediate variable... I personally find it clearer, but use whichever you (and your team) prefer.

Something like this
int count = (from p in Table1
where p.Department == "ABC" && p.Skill_Name != null
select p.Skill_Name).Distinct().Count();
For second query you can use this
var query= (from p in Customer
where p.Customer_Code=="1001"
select new { Location=p.location ,Country=p.country}).Distinct();

you can use linqpad to convert to linq and lambda expressions

Related

Unable to convert SQL query to linq query which contains subquery and need to handle two tables

We are converting a SQL query to a linq query, this conversion is involving two tables as follows:
select *
from Tbl_Vulpith_Registration
where Profile_Pic is not null
and MemId IN (select MemId from Tbl_List_Services)
Tbl_Vulpith_Registration and Tbl_List_Services are the two tables involved.
memId is the common column in the both the tables.
This is what we tried to convert the above SQL query to linq:
var reglist = objentity.Tbl_Vulpith_Registration.Select(a => a).Where(a => a.Profile_Pic != null);
var listmemsmemIds = objentity.Tbl_List_Services.Select(b => b.MemId).ToList();
var finalist = reglist.Select(b => b).Where(c => c.MemId.Contains(listmemsmemIds));
I guess MemId is a numeric type, if so, then you are using Contains wrong, correct your last statement to:
var finalist = reglist.Select(b => b).Where(c => listmemsmemIds.Contains(c.MemId));
Or even better, use the query syntax, it will get your result in one statement:
var finalist = (from a in objentity.Tbl_Vulpith_Registration
where a.Profile_Pic != null && (from b in objentity.Tbl_List_Services select b.MemId).Contains(a.MemId)
select a).ToList();
(from r in Tbl_Vulpith_Registration.Where(r => r.Profile_Pic != null)
from s in Tbl_List_Services.Where(s => s.MemId == r.MemId)
select r).ToList();
I believe you could also use this approach where you join these tables on the common MemId column.

Using lambda expressions on joined basic LINQ query

When making a basic LINQ query you can later use lambda expressions to add a where clause like this: query.Where(c => (init.Contains(c.user)));.
My problem is that I need to add two where clauses on a query that uses a join in the basic LINQ query.
I'm trying to replace my old basic LINQ queries with added lambda expressions so that i prevent duplicated code.
This is my code;
var query = from c in db.Clgcom
join u in db.Dvusr
on c.Comaut equals u.Gitusr
// && (initialen.Contains(c.Tstusr) // <-- query.Where(c => (initialen.Contains(c.Tstusr)));
// This is what im trying to replace// ^^ This works because its in the same table
// || initialen.Contains(u.Clgusr)) // <-- What do i type when i want to include both these conditions?
&& (c.Modid.StartsWith("C")
|| c.Modid.StartsWith("M"))
select c;
if(filter != null){
query = query.Where(c => (initialen.Contains(c.Tstusr)
|| initialen.Contains(u.Clgusr)));
// This doesn't work
}
Is there a way to use a lambda expression that would achieve adding these two conditions in my where clause?
Or should i replace ALL basic LINQ queries with using lambda expressions?
Basically you need to also defer the select by selecting both c and u to begin with and later just selecting c.
var temp = from c in db.Clgcom
join u in db.Dvusr on c.Comaut equals u.Gitusr
where c.Modid.StartsWith("C") || c.Modid.StartsWith("M")
select new {c, u};
if(filter != null){
temp = temp.Where(x => initialen.Contains(x.c.Tstusr)
|| initialen.Contains(x.u.Clgusr));
var query = temp.Select(x => x.c);
If the relationship between Clgcom and Dvusr is many to one then you could do the following as Clgcom should have a Dvusr navigation property based on the foreign key relationship.
var query = from c in db.Clgcom
where (c.Modid.StartsWith("C") || c.Modid.StartsWith("M")) && c.Dvuser != null
select c;
if(filter != null){
query = query.Where(c => initialen.Contains(c.Tstusr)
|| initialen.Contains(c.Dvusr.Clgusr));

comparison operator not supported for type int[] - linq to sql

Here is the problematic line:
var originalSummaryCandidates =
(from a in masterDB.tbl_thirty_second_summaries_multi_variant_associations
join d in masterDB.tbl_thirty_second_summaries_multi_variants on a.ThirtySecSummaryId equals d.ThirtySecondSummaryId_this
where d.DrugId == drugId &&
variantGenotypeIds.Contains(new int[] {a.VariantId, a.GenotypeId})
select d.ThirtySecondSummaryId_this)
.Distinct()
.ToList();
variantGeotpeIds is of type List<int[]>. Both a.VariantId and a.GenotypeId are of type int.
I cannot figure out why it why it will not do the comparison. Is this a deferred execution issue? It doesn't seem like it should be...
Thanks in advance.
List<T>.Contains only takes a single parameter of type T. In your case, T is Int32 but you're passing in a Int32[].
If you want to check that both values are in the list, you have to break the calls apart:
where d.DrugId == drugId &&
variantGenotypeIds.Contains(a.VariantId) &&
variantGenotypeIds.Contains(a.GenotypeId)
EDIT
If variantGenotypeIds is actually a List<Int32[]>, then there's another issue. LINQ to SQL will try to convert your query into its SQL equivalent. In this case, there's no way to translate your query into SQL so LINQ to SQL will throw an Exception.
If you really need to query this way, you'll have to read the records into memory first and then query using LINQ to Objects (which may or may not be a big deal depending on how many rows you are reading):
var query =
from a in masterDB.tbl_thirty_second_summaries_multi_variant_associations
join d in masterDB.tbl_thirty_second_summaries_multi_variants
on a.ThirtySecSummaryId equals d.ThirtySecondSummaryId_this
where d.DrugId == drugId
select new { a, d }
var originalSummaryCandidates =
(from q in query.AsEnumerable()
where variantGenotypeIds.Contains(new [] { q.a.VariantId, q.a.GenotypeId})
select d.ThirtySecondSummaryId_this)
.Distinct()
.ToList();
Array comparison uses reference equality by default. It's possible that linq-to-sql just tries to translate that into SQL that compares the values, but you'd have to look at the generated SQL to be sure. Another option would be to use Any instead:
where d.DrugId == drugId &&
variantGenotypeIds.Any(v => v[0] == a.VariantId && v[1] == a.GenotypeId)
but I'm not sure if Linq-to-Sql will be able to translate that to the correct SQL either. Another option would be to project the List` to a > and then do a string comparison:
variantGenotypeStrings = variantGenotypeIds.Select(v => string.Format("{0}|{1}", v[0],v[1]);
var originalSummaryCandidates =
(from a in masterDB.tbl_thirty_second_summaries_multi_variant_associations
join d in masterDB.tbl_thirty_second_summaries_multi_variants on a.ThirtySecSummaryId equals d.ThirtySecondSummaryId_this
where d.DrugId == drugId &&
variantGenotypeStrings.Contains(string.Format("{0}|{1}", a.VariantId, a.GenotypeId))
select d.ThirtySecondSummaryId_this)
.Distinct()
.ToList();

LINQ query to select top five

I have a LINQ query:
var list = from t in ctn.Items
where t.DeliverySelection == true && t.Delivery.SentForDelivery == null
orderby t.Delivery.SubmissionDate
select t;
How can I modify this query to select just five results from the database?
var list = (from t in ctn.Items
where t.DeliverySelection == true && t.Delivery.SentForDelivery == null
orderby t.Delivery.SubmissionDate
select t).Take(5);
The solution:
var list = (from t in ctn.Items
where t.DeliverySelection == true && t.Delivery.SentForDelivery == null
orderby t.Delivery.SubmissionDate
select t).Take(5);
This can also be achieved using the Lambda based approach of Linq;
var list = ctn.Items
.Where(t=> t.DeliverySelection == true && t.Delivery.SentForDelivery == null)
.OrderBy(t => t.Delivery.SubmissionDate)
.Take(5);
[Offering a somewhat more descriptive answer than the answer provided by #Ajni.]
This can also be achieved using LINQ fluent syntax:
var list = ctn.Items
.Where(t=> t.DeliverySelection == true && t.Delivery.SentForDelivery == null)
.OrderBy(t => t.Delivery.SubmissionDate)
.Take(5);
Note that each method (Where, OrderBy, Take) that appears in this LINQ statement takes a lambda expression as an argument. Also note that the documentation for Enumerable.Take begins with:
Returns a specified number of contiguous elements from the start of a
sequence.
Additional information
Sometimes it is necessary to bind a model into a view models and give a type conversion error. In this situation you should use ToList() method.
var list = (from t in ctn.Items
where t.DeliverySelection == true && t.Delivery.SentForDelivery == null
orderby t.Delivery.SubmissionDate
select t).Take(5).ToList();
Just thinking you might be feel unfamiliar of the sequence From->Where->Select, as in sql script, it is like Select->From->Where.
But you may not know that inside Sql Engine, it is also parse in the sequence of
'From->Where->Select', To validate it, you can try a simple script
select id as i from table where i=3
and it will not work, the reason is engine will parse Where before Select, so it won't know alias i in the where. To make this work, you can try
select * from (select id as i from table) as t where i = 3

"IN" Operator in Linq

I am trying to convert an old raw Sql query in Linq with Entity Framework here.
It was using the IN operator with a collection of items. The query was something like that:
SELECT Members.Name
FROM Members
WHERE Members.ID IN ( SELECT DISTINCT ManufacturerID FROM Products WHERE Active = 1)
ORDER BY Members.Name ASC
Since the return of the subquery is not a single string but a collection of strings I can't use the String.Contains() method.
I thought about doing something like :
var activeProducts = (
from products in db.ProductSet
where product.Active == true
select product.ManufacturerID);
and then
var activeMembers = (
from member in db.ContactSet
where member.ID.ToString().Contains(activeProducts));
but it stops at the contains saying it has invalid arguments ... I can't select activeProducts.ManufacturerID because obviously the proprety is not there since it returns an IQueryable...
Bottom line what I'm trying to do here is to return a list of members who have at least one active product.
Any hint ?
[edit]
Here's the full query code ... I tried with the contains on the second expression, Linq didn't seem to like it :
Server Error in '/' Application.
LINQ to Entities does not recognize the method 'Boolean Contains[String](System.Linq.IQueryable``1[System.String], System.String)' method, and this method cannot be translated into a store expression.
var activeProduct =(from product in Master.DataContext.ProductSet
where product.Active == true
&& product.ShowOnWebSite == true
&& product.AvailableDate <= DateTime.Today
&& ( product.DiscontinuationDate == null || product.DiscontinuationDate >= DateTime.Today )
select product.ManufacturerID.ToString() );
var activeArtists = from artist in Master.DataContext.ContactSet
where activeProduct.Contains(artist.ID.ToString())
select artist;
NumberOfArtists = activeArtists.Count();
artistsRepeater.DataSource = activeArtists;
artistsRepeater.DataBind();
[More details]
ManufacturerID is a nullable GUID apparently...
For some reason the ContactSet class do not contain any reference to the products I guess I will have to do a join query, no clues here.
var activeMembers = (
from member in db.ContactSet
where activeProducts.Select(x=>x.ID).Contains(member.ID));
Try where activeProducts.Contains(member.ID).
EDIT: Did you try it without any ToStrings?
You can do it in one query:
var q = from member in db.ContactSet
where member.Products.Any(p => p.IsActive)
select member;
Try the solution posted by Colin Meek at: http://social.msdn.microsoft.com/forums/en-US/adodotnetentityframework/thread/095745fe-dcf0-4142-b684-b7e4a1ab59f0/. It worked for me.
What about this:
from m in members
where products.FirstOrDefault(prod => prod.IsActive == 1 && prod.Id == m.Id) != null
select m;
you can chain any number of conditions required in the where clause using &&
Ash..
from m in members
where products.Any(p => p.Active && p.ManufacturerID == m.ID)
select m
or
from m in members
join p in products on m.ID equals p.ManufacturerID
where p.Active
select m
Instead of this:
var activeMembers = (
from member in db.ContactSet
where member.ID.ToString().Contains(activeProducts));
Try this:
var activeMembers = (
from member in db.ContactSet
where activeProducts.Contains(member.ID));
What if you swap the statement (untested)?
where activeProducts.Contains(member.ID)
How about this...
var activeProducts = (
from products in db.ProductSet
where product.Active == true
select product.ManufacturerID);
var activeMembers = (
from member in db.ContactSet
where activeProducts.Contains(member.ID.ToString()));
A helper or extension method will work fine when querying against objects in memory. But against an SQL database, your LINQ code will be compiled into an expression tree, analysed and translated into an SQL command. This functionality has no concept of custom-made extension methods or methods of other objects like .Contains(...).
It could be easily implemented into the standard LINQ-To-SQL functionality by Microsoft though. But as long as they don't want, we're helpless as long it's not an open source functionality.
All you can do is create your own QueryProvider that goes against an SQL database. But it will be hard and it would be only for that one in feature alone that you're missing.
However, if you really wanna go that route, have fun: LINQ: BUILDING AN IQUERYABLE PROVIDER SERIES
Finally I managed to code something really ugly, but that actually works! (lol)
var activeProduct =(from product in Master.DataContext.ProductSet
where product.Active == true
&& product.ShowOnWebSite == true
&& product.AvailableDate <= DateTime.Today
&& ( product.DiscontinuationDate == null || product.DiscontinuationDate >= DateTime.Today )
select product.ManufacturerID ).Distinct();
var artists = from artist in Master.DataContext.ContactSet
select artist;
List<Evolution.API.Contact> activeArtists = new List<Evolution.API.Contact>();
foreach (var artist in artists)
{
foreach(var product in activeProduct)
{
if (product.HasValue && product.Value == artist.ID)
activeArtists.Add(artist);
}
}
NumberOfArtists = activeArtists.Count();
artistsRepeater.DataSource = activeArtists;
artistsRepeater.DataBind();
I have already posted about the same at
http://www.codeproject.com/Tips/336253/Filtering-records-from-List-based-similar-to-Sql-I
var q = (from p in db.DOCAuditTrails
where p.ActionUser == "MyUserID"
&& p.ActionTaken == "Not Actioned"
&& p.ActionDate > DateTime.Parse("2011-09-13")
select p.RequisitionId).Distinct();
var DocAuditResults = db.DOCAuditTrails.Where(p
=> q.ToArray().Contains(p.RequisitionId));
Without know the exact mappings it is hard to tell what can be done and what can't. I will assume that there isn't any casting involved. Firstly you have to remember that everything in the Linq Expression tree must have an equivalent in SQL. As some others have noted, you have a object.ToString() in your Linq Statements.
However it seems that what people have neglected to mention is that you have TWO usages of object.ToSting(), both of which must be removed.
I would also make an extra variable to change the closure's capture type to be explicitly of DataContext (since the Linq statement is like a lambda, and delayed evaluated. It will need to take the whole of the Master variable. Earlier I stated that everything in your Linq must have an equivalent in SQL. Given that Master can't possibly exist in SQL, there is no DataContext property/column/mapping for the type of Master).
var context = Master.DataContext;
var activeProduct = from product in context.ProductSet
where product.Active == true
&& product.ShowOnWebSite == true
&& product.AvailableDate <= DateTime.Today
&& ( product.DiscontinuationDate == null || product.DiscontinuationDate >= DateTime.Today )
select product.ManufacturerID;
var activeArtists = from artist in context.ContactSet
where activeProduct.Contains(artist.ID)
select artist;
I hope the above changes work for you.
In many cases issues with Linq to ORMs can be traced back to your Linq Expression capturing a non primative (DateTime, int, string etc) and non ORM based class (DataContext/EntityObject etc). The other major gotcha is usage of functions and operators that aren't exposed by the ORM (it is possible to map user defined functions to .net function through the ORM, but I would not recommend it due to indexing issues).

Categories

Resources