Caveat: I know some parts of this code are bad, but it is what it is for now. I just want it to run properly. I fully intend to refactor later. I just need a working app right now.
The initial linq query grabs several fields of data, but more data must be added per item in the resultset. So, we have the foreach below. It grabs data and updates each row.
It overwrites everything to what I'm thinking is probably the last iteration of the foreach. Why? How do I keep it from overwriting?
Keep in mind that the working variable just meabns a period id. I want to get previous or future periods, and subtracting or adding to this allows this.
public List<intranetGS.Forecast> getForecast(int branchId) {
//user role protection here
intraDataContext q = new intraDataContext();
//this grabs the initial data
var basefc = (from f in q.fc_items
where f.color_option == false
select new intranetGS.Forecast {
itemId = f.item_id,
item = f.item_number,
itemDesc = f.description,
itemSuffix = f.item_suffix,
itemPrefix = f.item_prefix,
designation = f.designation
});
//now we filter
switch (getDesignation(branchId)) {
case 1:
basefc = basefc.Where(n => n.designation != 3);
basefc = basefc.Where(n => n.designation != 6);
break;
case 2:
basefc = basefc.Where(n => n.designation > 3);
break;
case 3:
basefc = basefc.Where(n => n.designation != 2);
basefc = basefc.Where(n => n.designation != 6);
break;
}
var current = Convert.ToInt32(DateTime.Now.Month);
var working = 0;
var year = Convert.ToInt32(DateTime.Now.Year);
List<intranetGS.Forecast> res = new List<intranetGS.Forecast>();
foreach (var f in basefc) {
working = getPeriod(current + "/" + (year - 1)); //starting with last year;
var ly = (from l in q.fc_forecasts where l.period == working && l.branch == branchId && l.item == f.itemId select l).FirstOrDefault();
if (!object.ReferenceEquals(ly, null)) {
f.lastYearForecast = ly.forecast;
f.lastYearReceipt = ly.receipt;
}
working = getPeriod(current + "/" + year) - 2; //two months ago
var m2 = (from l in q.fc_forecasts where l.period == working && l.branch == branchId && l.item == f.itemId select l).FirstOrDefault();
if (!object.ReferenceEquals(m2, null)) {
f.twoMosForecast = m2.forecast;
f.twoMosReceipts = m2.receipt;
f.twoMosUsage = m2.usage_lb;
}
working = getPeriod(current + "/" + year) - 1; //one month ago
var m1 = (from l in q.fc_forecasts where l.period == working && l.branch == branchId && l.item == f.itemId select l).FirstOrDefault();
if (!object.ReferenceEquals(m1, null)) {
f.oneMosForecast = m1.forecast;
f.oneMosReceipts = m1.receipt;
f.oneMosUsage = m1.usage_lb;
}
working = getPeriod(current + "/" + year); //current month
var m = (from l in q.fc_forecasts where l.period == working && l.branch == branchId && l.item == f.itemId select l).FirstOrDefault();
if (!object.ReferenceEquals(m, null)) {
f.currentMosForecast = m.forecast;
f.currentMosReceipts = m.receipt;
f.currentMosusage = m.usage_lb;
}
working = getPeriod(current + "/" + year) + 1; //one month from now
var mnext1 = (from l in q.fc_forecasts where l.period == working && l.branch == branchId && l.item == f.itemId select l).FirstOrDefault();
if (!object.ReferenceEquals(mnext1, null)) {
f.plusOneForecast = mnext1.forecast;
f.plusOneForecastId = mnext1.forcast_id;
}
working = getPeriod(current + "/" + year) + 2; //two months from now
var mnext2 = (from l in q.fc_forecasts where l.period == working && l.branch == branchId && l.item == f.itemId select l).FirstOrDefault();
if (!object.ReferenceEquals(mnext2, null)) {
f.plusTwoForecast = mnext2.forecast;
f.plusTwoForecastId = mnext2.forcast_id;
}
} //this is insanely and extremely cumbersome; refactor later.
return basefc;
}
UPDATE: It wasn't a list, it needed to be a list to avoid the overwrite.
The issue is that there is a delayed execution which occurs in linq as the user is building the query and internally it is building an expression tree where new expressions can be added. Once the query factors are settled upon during an execution, such as an enumerable target in a for loop or via .ToList() that list is fluid still. Since the code was simply adding more expressions and not filtering it out into a new list, the query just grew.
The question is when working on existing code, did the developer want to keep building the expression tree for performance or did they intend to make the items concrete at each step along the process?.
You may be fixing an issue by making the initial list concrete but could be introducing a logic bug going forward. Keep that in mind.
Related
I am having problems with subqueries in a linq-to-entities IQueryable query.
Can anybody tell me what is the correct way to do a sub query when building up an IQueryable query? Based on my full example below.
I get the following error when ToArray() is called on the query:
An exception of type 'System.NotSupportedException' occurred in System.Data.Entity.dll but was not handled in user code
Additional information: LINQ to Entities does not recognize the method 'System.Data.Entity.IDbSet`1[MyDomain.NewsWorthyPressReleases.NewsWorthyWire] Set[NewsWorthyWire]()' method,
and this method cannot be translated into a store expression.
So for example you can see one of my subqueries here:
BwIncluded = (from abw in Context.Set<NewsWorthyWire>()
where abw.WireId == PressWireIds.BUID
where abw.NewsWorthyCampaignId == nc.Id
select abw).Any(),
I am trying to populate BwIncluded with true or false if any() exists.
And the entire build up of the query is as follows, it is IMPORTANT to understand where the sub-queries are used:
private Func<EntityFramework.IDbContext, IQueryable<NewsWorthyPressRelease>> GetSearchNewsWorthyQuery(NewsWorthySearchFields searchFields)
{
return context =>
{
//domain models
var newsWorthyCampaigns = context.Set<NewsWorthyCampaign>();
var wires = context.Set<NewsWorthyWire>();
var campaigns = context.Set<Campaign>();
//predicates
var newsWorthyCampaignPredicate = PredicateBuilder.True<NewsWorthyCampaign>();
var wirePredicate = PredicateBuilder.True<NewsWorthyWire>();
var campaignPredicate = PredicateBuilder.True<Campaign>();
// build up the predicate queries
//Status was input
if (searchFields.StatusId.HasValue && searchFields.StatusId.Value > 0)
{
newsWorthyCampaignPredicate = newsWorthyCampaignPredicate.And(x => x.Id == searchFields.StatusId);
}
//Id was input
if (searchFields.Id.HasValue && searchFields.Id.Value > 0)
{
wirePredicate = wirePredicate.And(x => x.Id == searchFields.Id);
}
//Title was input
if (!string.IsNullOrEmpty(searchFields.Title))
{
wirePredicate = wirePredicate.And(x => x.Title.Contains(searchFields.Title));
}
//Wire was input
if (searchFields.PressWireId.HasValue && searchFields.PressWireId.Value > 0)
{
wirePredicate = wirePredicate.And(x => x.Id == searchFields.PressWireId);
}
//Created By was chosen
if (searchFields.CreatedById.HasValue && searchFields.CreatedById.Value > 0)
{
campaignPredicate = campaignPredicate.And(x => x.IdentityId == searchFields.CreatedById);
}
//Create Date From was chosen
if (searchFields.DateCreatedFrom.HasValue)
{
campaignPredicate = campaignPredicate.And(y => y.CreationDate >= searchFields.DateCreatedFrom);
}
//Create Date To was chosen
if (searchFields.DateCreatedTo.HasValue)
{
campaignPredicate = campaignPredicate.And(y => y.CreationDate <= searchFields.DateCreatedTo);
}
//the query
var nwprQuery = (from nc in newsWorthyCampaigns.Where(newsWorthyCampaignPredicate)
join w in wires.Where(wirePredicate)
on nc.Id equals w.NewsWorthyCampaignId
join c in campaigns.Where(campaignPredicate)
on nc.CampaignId equals c.Id
select new NewsWorthyPressRelease
{
Id = nc.Id,
Title = w.Title,
//BwIncluded = false,
//GnIncluded = false,
//PrIncluded = false,
BwIncluded = (from abw in Context.Set<NewsWorthyWire>()
where abw.WireId == PressWireIds.BUID
where abw.NewsWorthyCampaignId == nc.Id
select abw).Any(),
GnIncluded = (from agw in Context.Set<NewsWorthyWire>()
where agw.WireId == PressWireIds.GLID
where agw.NewsWorthyCampaignId == nc.Id
select agw).Any(),
PrIncluded = (from anw in Context.Set<NewsWorthyWire>()
where anw.WireId == PressWireIds.PRID
where anw.NewsWorthyCampaignId == nc.Id
select anw).Any(),
CreatedBy = c.CreatedBy.FirstName + " " + c.CreatedBy.Surname,
CreateDate = c.CreationDate,
Status = nc.NewsWorthyStatus.Name,
}).AsNoTracking();
return nwprQuery;
};
}
Can anyone help with this?
Thanks
I'm trying to write a linq query that uses an if statement.
In the code below I'm searching for matches of
n.SAU_ID = sau.SAUID where
ReportingPeriod column contains "Oct1" then
FiscalYear - aprYearDiff = sau.SAUYearCode.
Else
FiscalYear - octYearDiff = sau.SAUYearCode.
My code is only giving matches for the SAUID and "Oct1".
What code is needed to implement theese statements?
int FiscalYear = 2014;
List<String> addtowns = new List<string>();
List<Stage_Reorg> reorg = _entities.Stage_Reorg.ToList();
int aprYearDiff = 2;
int octYearDiff = 1;
foreach (var sau in reorg)
{
addtowns.AddRange(_entities.Stage_EPSSubsidySADCSDTown
.Where(n => n.SAU_ID == sau.SAUID
&& (n.ReportingPeriod == "Oct1"
? (FiscalYear - aprYearDiff) == sau.SAUYearCode
: (FiscalYear - octYearDiff) == sau.SAUYearCode))
.Select(n => n.TownCode ));
}
This is a bad idea anyway. Transform the condition to
(n.ReportingPeriod == "Oct1" && (FiscalYear - aprYearDiff) == sau.SAUYearCode)
|| (n.ReportingPeriod != "Oct1" && (FiscalYear - octYearDiff) == sau.SAUYearCode)
Here is a possible way but this probably won't work with EF. You will need to load all records into memory then perform the filtering:
addtowns.AddRange(_entities.Stage_EPSSubsidySADCSDTown
.Where(n => {
bool b = n.ReportingPeriod == "Oct1"
? (FiscalYear - aprYearDiff) == sau.SAUYearCode
: (FiscalYear - octYearDiff) == sau.SAUYearCode);
return b && n.SAU_ID == sau.SAUID;
}).Select(n => n.TownCode ))
I am looking to run a piece of code in the database. However there is no supported translation to sql (using linq to sql).
How to convert this code logic ro either inline in linq or in a stored procedure? I have no knowledge of db and stored procedures so preferably I would like to write it in linq.
public Post GetPageOwner(int pageid)
{
var posts = (from dp in db.Posts where dp.pageid == pageid select dp);
var returned = posts;
if (posts.Count() > 0)
{
var latest = posts.OrderByDescending(o => o.Date).FirstOrDefault();
var sharedsamedayaslatest = (from p in posts where p.Date.AddDays(1) >= latest.Date select p);
if (sharedsamedayaslatest.Count() > 1)
{
var followedpost = (from p in posts from s in db.Subscriptions where s.Subscriber == UID && s.Subscribedto == p.UserId select p);
var count = followedpost.Count();
if (count == 1)
{
returned = followedpost;
}
else if (count > 1)
{
returned = (from s in followedpost let reposts = GetPostReposts(s.id) let rating = GetPostRating(s.id) let score = reposts + rating orderby score descending select s);
}
else
{
//no follower shared this post so return the most liked
returned = (from s in sharedsamedayaslatest let reposts = GetPostReposts(s.id) let rating = GetPostRating(s.id) let score = reposts + rating orderby score descending select s);
}
}
else
{
//no shares on the day the latest share
returned = sharedsamedayaslatest;
}
}
else
{
//only one post
returned = posts;
}
return returned.FirstOrDefault(); //order by userid gets a random one
}
May be something like this would work:
public Post GetPageOwner(int pageid)
{
var posts = (from dp in db.Posts where dp.pageid == pageid select dp);
var returned = posts;
if (posts.Count() > 0)
{
var latest = posts.OrderByDescending(o => o.Date).FirstOrDefault();
var sharedsamedayaslatest = (posts.Where(p => p.Date.AddDays(1) >= latest.Date));
if (sharedsamedayaslatest.Count() > 1)
{
var followedpost = (posts.SelectMany(p => db.Subscriptions, (p, s) => new {p, s}).Where(
#t => s.Subscriber == UID && s.Subscribedto == p.UserId).Select(#t => p));
var count = followedpost.Count();
if (count == 1)
{
returned = followedpost;
}
else if (count > 1)
{
returned = (followedpost.Select(s => new {s, reposts = GetPostReposts(s.id)}).Select(
#t => new {#t, rating = GetPostRating(s.id)}).Select(
#t => new {#t, score = reposts + rating}).OrderByDescending(#t => score).Select(#t => s));
}
else
{
//no follower shared this post so return the most liked
(sharedsamedayaslatest.Select(s => new {s, reposts = GetPostReposts(s.id)}).Select(
#t => new {#t, rating = GetPostRating(s.id)}).Select(
#t => new {#t, score = reposts + rating}).OrderByDescending(#t => score).Select(#t => s)) = returned;
}
}
else
{
//no shares on the day the latest share
returned = sharedsamedayaslatest;
}
}
else
{
//only one post
returned = posts;
}
return returned.FirstOrDefault(); //order by userid gets a random one
}
string NewsFillter = string.Empty;
List<string> PublishDatePostMeta = (from post in postrepository.GetAllPosts()
join pstmt in postrepository.GetAllPostMetas()
on post.int_PostId equals pstmt.int_PostId
where (post.int_PostTypeId == 4 && post.int_PostStatusId == 2 && post.int_OrganizationId == layoutrep.GetSidebarDetailById(SidebarDetailsId).int_OrganizationId) && pstmt.vcr_MetaKey=="Publish Date"
select pstmt.vcr_MetaValue).ToList();
int DatesCount = PublishDatePostMeta.Count();
foreach (string PublishDate in PublishDatePostMeta)
{
if (PublishDate != "")
{
NewsFillter += System.DateTime.Now + ">=" + Convert.ToDateTime(PublishDate);
}
}
var postsidebar = from post in postrepository.GetAllPosts()
join pstmt in postrepository.GetAllPostMetas()
on post.int_PostId equals pstmt.int_PostId
where (post.int_PostTypeId == 4 && post.int_PostStatusId == 2 && post.int_OrganizationId == layoutrep.GetSidebarDetailById(SidebarDetailsId).int_OrganizationId)
&& (pstmt.vcr_MetaKey.Contains(filter) && pstmt.vcr_MetaValue.Contains("true"))
select post;
1st question .The thing is that how NewsFillter would be accomdated in the postsidebar query in the pstmt object after true ( i would be putting it in contains,equals join or what) .
2nd question . is there any way that a chunk (between &&s) return enumerable and i can get away with this. at this moment it is not allowing that
I haven't udnerstood you properly, but if you want to apply multiple filters, here is my solution:
//Book is a table in the database
List<Expression<Func<Book, bool>>> filters = new List<Expression<Func<Book, bool>>>();
IQueryable<Book> query = dc.Books;
filters.Add(b => b.BookId == long.Parse(id));
//apply all filters
foreach (var f in filters)
query = query.Where(f);
Your questions:
This question requires an example of input and output. Try something like this:
|| pstmt.vcr_MetaKey=="Publish Date" && (
pstmt.vcr_MetaValue == "" || DateTime.Parse(pstmt.vcr_MetaValue) < DateTime.Now)
There is method AsEnumerable, if you mean what I think.
Still really struggling with this and appear to be going round in circles.
I have the following code that is driving me nuts. It should populate a list of items to be used in an autocomplete text box:
public string[] GetAutoComplete(string prefixText, int count)
{
string memberid = HttpContext.Current.Session["MemberID"].ToString();
string locationid = HttpContext.Current.Session["LocationID"].ToString();
string inhouse = HttpContext.Current.Session["Inhouse"].ToString();
string supplier = HttpContext.Current.Session["Supplier"].ToString();
string groupw = HttpContext.Current.Session["Group"].ToString();
string external = HttpContext.Current.Session["External"].ToString();
MyEnts autocomplete = new MyEnts();
var r = from p in autocomplete.tblAutoCompletes
where p.MemberId == memberid && p.LocationId == locationid && p.ACItem.Contains(prefixText)
select p.ACItem;
if (inhouse == "Inhouse")
r = r.Where(p => p == inhouse);
if (supplier == "Supplier")
r = r.Where(p => p == supplier);
if (groupw == "Group")
r = r.Where(p => p == groupw);
if (external == "External")
r = r.Where(p => p == external);
r.OrderBy(p => p);
return r.ToArray();
What I am trying to retrieve with the dynamic where clause along the lines of the following.
Should inhouse = "Inhouse", then the list of items should include the word "Inhouse". If inhouse != "Inhouse", the word "Inhouse" should be excluded from the list.
This same logic should then be applied across the different where clauses i.e. Supplier, Group, External.
I genuinely have tried lots of different methods but I cannot for the life of me get the thing to work and it's frustrating me somewhat.
If anyone can suggest a way of doing this, you will either get a big kiss or a big frosty beer should our paths ever cross.
Not exactly sure about your problem here but if you want to exclude then shouldn't the code be something like
if (inhouse == "Inhouse")
r = r.Where(p => p == inhouse);
else
r = r.Where(p => p != inhouse);
Oh! if you want just exclusion then the code should be something like
if (inhouse != "Inhouse")
r = r.Where(p => p != inhouse);
If the set of values to include/exclude is known at compile-time (as appears to be the case in your example), I think this can be managed with one query:
string memberid = HttpContext.Current.Session["MemberID"].ToString();
string inhouse = HttpContext.Current.Session["Inhouse"].ToString();
string supplier = HttpContext.Current.Session["Supplier"].ToString();
bool includeInHouse = (inhouse == "Inhouse");
bool includeSupplier = (supplier == "Supplier");
MyEnts autocomplete = new MyEnts();
var r = from p in autocomplete.tblAutoCompletes
where (p.MemberId == memberid && p.LocationId == locationid && p.ACItem.Contains(prefixText))
&& (includeInHouse || (p.ACItem != "InHouse"))
&& (includeSupplier || (p.ACItem != "Supplier"))
select p.ACItem;
r.OrderBy(p => p.ACItem);
return r.ToArray();
I've eliminated a couple cases for brevity.
Wouldn't each of your Where clauses just need to contain a Contains criteria and some Not Contains?
if (inhouse == "Inhouse")
r = r.Where(p => p.Contains(inhouse) && !p.Contains("Supplier") && !p.Contains("Group") && !p.Contains("External"));
Sorted.
var r = from p in autocomplete.tblAutoCompletes
where p.MemberId == memberid && p.LocationId == locationid && p.ACItem.Contains(prefixText)
select p.ACItem;
if (inhouse != "Inhouse")
r = r.Where(p => p != "Inhouse");
if (supplier != "Supplier")
r = r.Where(p => p != "Supplier");
if (groupw != "Group")
r = r.Where(p => p != "Group");
if (external != "External")
r = r.Where(p => p != "External");
r = r.OrderBy(p => p);
return r.ToArray();
I had to set the exception in quotation marks as the session vlaue was inappropriate and wouldn't have picked out anything from the list.
Thanks to all those contributing and helping me out.