Good practice for using "NOT IN" in a LINQ query - asp.net-mvc-3

I have converted the following SQL query to LINQ with the exception of the "NOT IN" subquery.
What would be the most effective way to implement this using LINQ? Should I use a join instead?
If anybody is able to provide an example or some guidance, I'd appreciate it.
New LINQ Query:
return from objOpenCalls in db.OpenItemss
from objTasks in db.Tasks
.Where(t => (t.Task_ID == objOpenCalls.Parent_Task_ID))
where ((objTasks.Item_ID > 0) && (objTasks.Type_ID > 0) && (objTasks.OwnerTypeItem_ID == user) && (objOpenCalls.CallEnd < DateTime.Now))
orderby objOpenCalls.CallStart descending
select new CallMiniViewModel
{
ID = objOpenCalls.ID,
CallStart = objOpenCalls.CallStart,
Name = objTasks.Task_Title
};
Old SQL Query:
SELECT TOP (100) ta.ID, t.Task_Title, ta.CallStart
FROM OpenItems AS ta INNER JOIN
Tasks AS t ON ta.Parent_Task_ID = t.Task_ID
WHERE
(t.Item_ID > 0) AND (t.[Type_ID] > 0) AND (ta.CallStart > DATEADD(m, -6, GETDATE()))
AND (ta.ID NOT IN (SELECT CallId FROM CallFeedback)) AND (t.OwnerTypeItem_ID = #Username) AND (ta.CallEnd < GETDATE())
ORDER BY ta.CallStart DESC

There are a couple of ways of doing the not in. Below is just a quick sample put in LinqPad as a test.
class MyClass {
public int Id {get;set;}
}
void Main()
{
int[] myItems = new[] { 1, 2, 3, 4, 5, 6 };
IEnumerable<MyClass> classes = new []{
new MyClass { Id = 3 },
new MyClass { Id = 6 },
new MyClass { Id = 8 }
};
var results = from cl in classes
where !myItems.Contains( cl.Id )
select cl;
foreach(var result in results) {
Console.WriteLine( "Class {0}", result.Id);
}
var results2 = from cl in classes
where (
from i in myItems
where i == cl.Id
select i ).Count( ) == 0
select cl;
foreach(var result in results2) {
Console.WriteLine( "Class {0}", result.Id);
}
}
I normally play with code first in LinqPad as it helps me understand any problems, and it will (if you're working with SQL) then show you what SQL the query will generate and you can fine tune a little. Sometimes it takes a little time to get your stuff able to be run in there, but it's worth it with the more complex queries.

Related

How to Sortby Multiple Colums - Linq to SQL

Wanting to sortby x.IRNumber - .thenby x.BedLocation but no luck could someone help me in the right direction?
Thanks
Mark
string jobID = ddlJobID.SelectedValue;
using (rw_forms context = new rw_forms())
{
var result = from c in context.hospedia_running_sheet_view.Select(x => new
{
x.uniqueID,
x.irNumber,
x.ward,
x.bed_location,
x.bed_extension,
x.select_technology,
x.select_fitting_of_pattress,
x.select_fitting_of_backplate,
x.fixing_method_used,
x.id,
x.status,
x.latitude,
x.longitude,
x.accuracy,
x.createdAt,
x.createdByName,
x.fixing,
x.statusID,
x.commissioningID,
x.jobID,
x.siteName
}).Where(x=> x.statusID == 1).Where(x => x.jobID == ((jobID == "-1") ? x.jobID : jobID)).OrderByDescending(x => x.irNumber) select c;
grdForms.DataSource = result.ToList();
grdForms.DataBind();
}
}
catch(Exception ex)
{
Response.Write(ex.ToString());
}
}
If you want something like this
SELECT * FROM TEST
ORDER BY TEST.ID,TEST.RID DESC
-
from t in db.TEST
orderby t.ID, t.RID descending
select t

Problem returning an IEnumerable<T>/IList<T>

I am having trouble to return an IEnumerable and IList, I cant do it!
I am using EF 4 with POCOs
Here's the whole method:
//public IList<Genre> GetGenresByGame(int gameId)
public IEnumerable<Genre> GetGenresByGame(int gameId)
{
using(var ctx = new XContext())
{
var results =
from t0 in ctx.GameGenres
join t1 in ctx.GenreCultureDetails on t0.GenreId equals t1.GenreId
where t0.GameId == gameId && t1.CultureId == _cultureId
select new Genre
{
GenreId = t0.GenreId,
GenreName = t1.GenreName
};
return results.ToList();
}
}
I have tried different ways that I have found on the net.. but can't make it work!
Question 2:
I saw a screencast with Julie something, saying that "You should always return an ICollection" when using EF4.
Any thoughts about that ?
BR
EDIT:
When I load the page in Debug-mode i get these errors: The ObjectContext instance has been disposed and can no longer be used for operations that require a connection. OR The entity or complex type 'XModel.Genre' cannot be constructed in a LINQ to Entities query.
Genre must not be a L2EF type. Try this:
public IEnumerable<Genre> GetGenresByGame(int gameId)
{
using(var ctx = new XContext())
{
var resultList =
from t0 in ctx.GameGenres
join t1 in ctx.GenreCultureDetails on t0.GenreId equals t1.GenreId
where t0.GameId == gameId && t1.CultureId == _cultureId
select new { t0.GenreId, t1.GenreName };
var genres = resultList.AsEnumerable().Select(o => new Genre
{
GenreId = o.GenreId,
GenreName = o.GenreName
});
return genres.ToList();
}
}
First an foremost if Genre is in the database you should select it? If you have FKs from Genre->GenreCultureDetails let me know and I can update the below, but from the looks of it you could do it like this:
using(var ctx = new XContext())
{
var results =
from g in ctx.Genre
join gcd in ctx.GenreCultureDetails on g.GenreId equals gcd.GenreId
where g.GameId == gameId && gcd.CultureId == _cultureId
select g;
return result.ToList();
}
Alternatively continue down your path select them into an annoynmous type, and then copy them. You can use select instead of convertall if you please.
IList<Genre> returnMe = Null;
using(var ctx = new XContext())
{
var results =
from t0 in ctx.GameGenres
join t1 in ctx.GenreCultureDetails on t0.GenreId equals t1.GenreId
where t0.GameId == gameId && t1.CultureId == _cultureId
select new
{
GenreId = t0.GenreId,
GenreName = t1.GenreName
};
returnMe = results.ToList().ConvertAll(x=>new Genre(){
GenreId = x.GenreId,
GenreName = x.GenreName
}
);
}
return returnMe;

Using Custom Function in Linq Query

I'm using L2S for database operations in my asp.net mvc application I have following simple query in my repository
(from pt in db.oaProjectTasks
where pt.ProjectID == ProjectID
join t in db.oaTasks on pt.TaskID equals t.TaskID
where t.ParentTaskID == null
let daypassed = GetDaysPassed(t.StartDate,t.Duration)
select new ChartTask{TaskNumber = t.TaskNumber,StartDate = t.StartDate,
DurationRemaining = t.Duration - daypassed,TaskDescription = t.Task, DaysPassed = daypassed,Duration = t.Duration }).ToList();
below is the defination of GetDayPassed method
private int GetDaysPassed(DateTime StartDate, int Duration)
{
int retVal;
if ((DateTime.Now - StartDate).Days > 0)
{
if ((DateTime.Now - StartDate.AddDays(Duration)).Days > 0)
{
retVal = Duration;
}
else
{
retVal = (DateTime.Now - StartDate).Days;
}
}
else
{
retVal = 0;
}
return retVal;
}
there is no compile time error, however, when i execute the code it gives me invalidOperationException with following message.
Could not translate expression 'Table(oaProjectTask).Where(pt => (pt.ProjectID == Invoke(value(System.Func`1[System.Int64])))).Join(Table(oaTask), pt => pt.TaskID, t => t.TaskID, (pt, t) => new <>f__AnonymousType5f`2(pt = pt, t = t)).Where(<>h__TransparentIdentifier2 => (<>h__TransparentIdentifier2.t.ParentTaskID == null)).Select(<>h__TransparentIdentifier2 => new
how can I get around this? if calling a method in query is not allowed how can I make a simple calculation in Linq query instead of calling GetDayPassed method?
You can try this:
(from pt in db.oaProjectTasks
where pt.ProjectID == ProjectID
join t in db.oaTasks on pt.TaskID equals t.TaskID
where t.ParentTaskID == null
select t)
.ToList() // T-SQL query will be executed here and result will be returned
.Select(t => new ChartTask {
TaskNumber = t.TaskNumber,
StartDate = t.StartDate,
DurationRemaining = t.Duration - GetDaysPassed(t.StartDate,t.Duration),
TaskDescription = t.Task,
DaysPassed = GetDaysPassed(t.StartDate,t.Duration),
Duration = t.Duration });
The problem is that Linq to Sql tries to translate your custom function to T-SQL and since it doesn't know how to do that it will throw the exception. In my case Linq will construct the query, execute it (after the call to .ToList()) and your function will be called as Linq to objects query.

LINQ refactoring help needed

How would you refactor this code, with respect to the LINQ? I'm new to LINQ and haven't quite have a good handle on more complex queries (nested, grouping).
Can all of these three statements and foreach loop been converted into one LINQ statement?
void AddSeries(Series series, int phraseId)
{
using (var db = Database.Instance)
{
foreach (var date in db.Ad.Select(ad => ad.DateTime.Date).Distinct())
{
var phraseCount = (from pc in db.PhraseCount
where pc.DateTime.Date == date &&
pc.PhraseId == phraseId
select pc.Count).SingleOrDefault();
var adCount = db.Ad.Where(ad => ad.DateTime.Date == date).Count();
series.Add(date, phraseCount / adCount);
}
}
}
Here's my first shot. Hard without having your model.
var q = from ad in db.Ad
group ad by ad.DateTime.Date into g
select new
{
AdCount = g.Count(),
Date = g.Key,
PhraseCount = (from pc in db.PhraseCount
where pc.DateTime.Date == g.Key
&& pc.PhraseId == phraseId
select pc).Count()
}

How To Project a Line Number Into Linq Query Results

How can I project the row number onto the linq query result set.
Instead of say:
field1, field2, field3
field1, field2, field3
I would like:
1, field1, field2, field3
2, field1, field2, field3
Here is my attempt at this:
public List<ScoreWithRank> GetHighScoresWithRank(string gameId, int count)
{
Guid guid = new Guid(gameId);
using (PPGEntities entities = new PPGEntities())
{
int i = 1;
var query = from s in entities.Scores
where s.Game.Id == guid
orderby s.PlayerScore descending
select new ScoreWithRank()
{
Rank=i++,
PlayerName = s.PlayerName,
PlayerScore = s.PlayerScore
};
return query.ToList<ScoreWithRank>();
}
}
Unfortunately, the "Rank=i++" line throws the following compile-time exception:
"An expression tree may not contain an assignment operator"
Well, the easiest way would be to do it at the client side rather than the database side, and use the overload of Select which provides an index as well:
public List<ScoreWithRank> GetHighScoresWithRank(string gameId, int count)
{
Guid guid = new Guid(gameId);
using (PPGEntities entities = new PPGEntities())
{
var query = from s in entities.Scores
where s.Game.Id == guid
orderby s.PlayerScore descending
select new
{
PlayerName = s.PlayerName,
PlayerScore = s.PlayerScore
};
return query.AsEnumerable() // Client-side from here on
.Select((player, index) => new ScoreWithRank()
{
PlayerName = player.PlayerName,
PlayerScore = player.PlayerScore,
Rank = index + 1;
})
.ToList();
}
}
Ok, that did the trick. Thanks.
Here is my final code...
Server:
public List<Score> GetHighScores(string gameId, int count)
{
Guid guid = new Guid(gameId);
using (PPGEntities entities = new PPGEntities())
{
var query = from s in entities.Scores
where s.Game.Id == guid
orderby s.PlayerScore descending
select s;
return query.ToList<Score>();
}
}
Client:
void hsc_LoadHighScoreCompleted(object sender, GetHighScoreCompletedEventArgs e)
{
ObservableCollection<Score> list = e.Result;
_listBox.ItemsSource = list.Select((player, index) => new ScoreWithRank()
{
PlayerName = player.PlayerName,
PlayerScore = player.PlayerScore,
Rank = index+=1
}).ToList();
}
You could also make just a slight adjustment to your original code to get it working. Word of caution, if you databind or access the object again, the Rank will increment each time. In those cases the top answer is better.
let Rank = i++
and
Rank.ToString()
Full code:
public List<ScoreWithRank> GetHighScoresWithRank(string gameId, int count)
{
Guid guid = new Guid(gameId);
using (PPGEntities entities = new PPGEntities())
{
int i = 1;
var query = from s in entities.Scores
let Rank = i++
where s.Game.Id == guid
orderby s.PlayerScore descending
select new ScoreWithRank()
{
Rank.ToString(),
PlayerName = s.PlayerName,
PlayerScore = s.PlayerScore
};
return query.ToList<ScoreWithRank>();
}
}
This solution worked for me.
http://www.dotnetfunda.com/articles/article1995-rownumber-simulation-in-linq.aspx
.Select((x, index) => new
{
SequentialNumber = index + 1
,FieldFoo = x.FieldFoo
}).ToList();
List<Emp> Lstemp = GetEmpList();
int Srno = 0;
var columns = from t in Lstemp
orderby t.Name
select new {
Row_number=++Srno,
EmpID = t.ID,
Name = t.Name,
City = t.City
};

Resources