Need help converting SQL to EF4 please - c#

I need help converting this SQL statement, into EF4:
Select Posts.PostID, Post, Comment
from Posts left join
Comments on posts.PostID = Comments.PostID
Where CommentID not in
(
Select PostID
from Votes
where VoteTypeID = 4 --4 = flagged comment type
)
In my database, the Votes table stores either the PostID of reported posts, or CommentID of reported comments in the column Votes.PostID
Thanks in advance!

using (var context = new Model1Container())
{
var posts = context.Posts.
All((p)=> p.Votes.All((v) => v.VoteTypeId!=4));
//Or
var posts2 = from p in context.Posts
where p.Votes.All((v)=> v.VoteTypeId != 4)
select p;
}
Update:
Based on my understanding you want all the posts, but for each post, you want to filter its comments, if that's the case, you could use ToDictionary:
var posts =
context.Posts.
//Include("Comments").
ToDictionary(
(p) => p,
(p) => p.Comments.Where((c)=> c.Votes.All((v) => v.VoteTypeId !=4))
);
foreach (var item in posts)
{
var post = item.Key;
var comments = item.Value;
}
Note: uncomment the Include method if lazy-loading is disabled, and you explicitly want to eager-load the comments in this query.
Update2:
var postsCollection = posts.Keys.ToArray();
var commentsCollection = posts.Values.ToArray();

This is hard to determine without seeing your Model. But this should get you started.
If you would like you can post a picture of your model or the EDMX and I can take a better look at this.
var myPosts = from p in posts
where !p.Comments.Any(c => c.Votes.VoteID != 4)
PostId = p.PostId,
//other field needed here
};

Related

Linq replace column value with another value

Well, im doing a linq query to get a list of results with the same column, and then i need to replace that column value with a new one.
First Code:
var db = GetContext();
var result = from f in GetContext().ProjectStateHistories
where f.ProjectId.Equals(oldProjectId)
select f;
foreach (var item in result)
{
var projectStateHistoryUpdate = db.ProjectStateHistories.Find(item.Id);
projectStateHistoryUpdate.ProjectId = newProjectId;
db.Entry(projectStateHistoryUpdate).State = EntityState.Modified;
}
db.SaveChanges();
I searched for some answers, and i found that i can use Select, and make a new object (Linq replace null/empty value with another value)
Second Code:
var result = (from f in GetContext().ProjectStateHistories
where f.ProjectId.Equals(oldProjectId)
select f).Select(d=> new { Id = d.Id, EventName = d.EventName, LogUser = d.LogUser, ProjectId = newProjectId, TimeStamp = d.TimeStamp });
And even, Third Code:
var db = GetContext();
var result = (from f in db.ProjectStateHistories
where f.ProjectId.Equals(oldProjectId)
select f).Select(d=> new { ProjectId = newProjectId});
But only the First Code works.
I wanted to ask what i am doing wrong, since i think it is better to change the value with a query, instead of using a foreach.
See code below:
var db = GetContext();
(from f in db.ProjectStateHistories
where f.ProjectId.Equals(oldProjectId)
select f)
.ToList()
.ForEach(i => i.ProjectId = newProjectId);
db.SaveChanges();
Alternatively:
var db = GetContext();
db.ProjectStateHistories
.Where(f => f.ProjectId.Equals(oldProjectId))
.ToList()
.ForEach(f => f.ProjectId = newProjectId);
db.SaveChanges();
The shortest way I know of to replace your code is this:
var db = getcontext();
db.ProjectStateHistories
.Where(f => f.ProjectId.Equals(oldProjectId))
.ToList()
.ForEach(f => f.ProjectId = newProjectId);
db.SaveChanges();
Other answers can be found here
I've just had a thought that could help you, I am just free coding here!
If you just put the for each as part of the select, and then save your changes will that work?
foreach (var source in db.ProjectStateHistories.Where(x => x.ProjectId == oldProjectId))
{
source.ProjectId= newProjectId;
db.Entry(source).State = EntityState.Modified;
}
db.SaveChanges();
I think this is a more efficient way of doing it.
Also the .Select() method is only really useful if you need to Project to a view Model, it won't change the variables in the database, just show them in the newly declared object.
Thanks,
Phill

The query processor ran out of internal resources and could not produce a query plan in EF

I have a query in EF where there is a List of string value that it checks for existence in another table.
Please consider the below query for more details.
Code
List<string> ItmsStock = item.Select(ds => ds.ItemNum).ToList(); // Currently, This List items count is 80,000 records.
this.Db.Database.CommandTimeout = 180;
var existsStckList = Db.Stocktakes.Where(ds => ItmsStock.Contains(ds.ItemNo)).Select(ds => ds.ItemNo).ToList();
item.RemoveAll(ds => existsStckList.Contains(ds.ItemNum));
var ItmsExists = Db.Items.Where(ds => ItmsStock.Contains(ds.ItemNo)).Select(ds => ds.ItemNo).ToList();
ItmsExists = Db.Stocktakes.Where(ds => !ItmsExists.Contains(ds.ItemNo)).Select(ds => ds.ItemNo).ToList();
I searched on the internet and found the converted sql uses IN to check for existence. so, the limit for the IN makes the problem. My question here is, How can I efficiently perform the above actions without using for loop.
I ll be appreciating you, If anybody can help me out.
Edit
Previously, I had the below code. After facing the performance issue with the below code, I wrote the above one.
foreach (var stockitems in item)
{
if (Db.Stocktakes.Any(a => a.ItemNo == stockitems.ItemNum))
{
StockResult ss = new StockResult();
ss.ItemNumber = stockitems.ItemNum;
ss.FileName = stockitems.FileName;
Stockres.Add(ss);
}
else if (!Db.Stocktakes.Any(a => a.ItemNo == stockitems.ItemNum) && Db.Items.Any(a => a.ItemNo == stockitems.ItemNum))
{
var ItemNo = stockitems.ItemNum;
var AdminId = Convert.ToInt32(Session["AccId"]);
var CreatedOn = System.DateTime.Now;
int dbres = Db.Database.ExecuteSqlCommand("insert into Stocktake values({0},{1},{2})", ItemNo, AdminId, CreatedOn);
Db.SaveChanges();
totalcount = totalcount + 1;
}
else
{
StockResult sss = new StockResult();
sss.ItemNumber = stockitems.ItemNum;
sss.FileName = stockitems.FileName;
Stockitemsdup.Add(sss);
}
}
Thanks.
Issue batches of 1000 item IDs to the database, or use native SQL and submit a table-valued parameter, or a temp table filled with SqlBulkCopy.
I'm surprised you got htis particular message. The parameter limit is about 2000 parameters. Your query should have been rejected.

linq to sql complex query with group by

I have a table called "Articles".
it includes the following field:
ArticleIndex, ArticleLevel, ArticleParentIndex.
I made query which returns all the articles with ArticleLevel=1 - let's call it query1.
The query which returns all the articles with ArticleLevel=2 - query2.
I would like to have a query that would return Articles of level=1 with at least one child article (the child articles have level=2), and also the number of child articles.
So far I have the following query:
var filteredItemsGrouped = from i in filteredItems
group i by i.ArticleParentIndex into g
select new { Node = g, NodeItemsCount = g.Count() };
and then, in order to get the actual articles with level=1 I do:
IList<ArticleNodeInfo> Nodes = new List<ArticleNodeInfo>();
foreach (var node in filteredItemsGrouped)
{
Nodes.Add(new ArticleNodeInfo
{
Node = articlesService.GetArticleByIndex((int)(node.Node.FirstOrDefault().ArticleParentIndex)),
NodeItemsCount = node.NodeItemsCount
});
}
This process is too expensive. Is it possible to acheive the same with one query (instead of retreiving by article index every time)?
Hope I'm clear enough...
this should do the trick:
var articlesLevel1 = (
from al1 in Articles
join al2 in Articles on new
{
al1.ArticleIndex,
ArticleLevel = 2
} equals new
{
ArticleIndex = al2.ArticleParentIndex,
al2.ArticleLevel
} into g_al2
where (al1.ArticleLevel == 1) && g_al2.Any()
select new
{
ArticlesLevel1 = al1,
ArticlesLevel2Count = g_al2.Count()
});

Getting rid of nested foreach loops when using linq

I am always finding myself creating linq expressions that still use nested foreach loops heavily. Below is a simple example of what I'm talking about, and I'd really appreciate it if someone on here can show me how to condense this low-efficiency code into a single linq expression?
The database context (db) has three tables: Blog, Tag, Junc_Tag_Blog. The junction table simply stores a record of blogs with their tags.
Anyway, here's my messy code:
public static Collection<Blog> GetByTag(string tagName)
{
// Get the tag record.
var tag = (from t in db.Tags
where t.Name == tagName
select t).Single();
// Get the list of all junction table records.
var tagJunc = from tj in db.Junc_Tag_Blogs
where tj.Fk_Tag_Id == tag.Id
select tj;
// Get a list of all blogs.
var blogs = from b in db.BlogPosts
select b;
// Work out if each blog is associated with given tag.
foreach(var blog in blogs)
{
foreach(var junc in tagJunc)
{
if(blog.Id == junc.Fk_Blog_Id)
{
// We have a match! - do something with this result.
}
}
}
}
Thanks in advance to the person who can help me clean this code up!
You can construct a query that lets the database find the matches for you.
List<Blog> blogs =
(
from t in tag
where t.Name == tagName
from tj in t.Junc_Tag_Blogs
let b = tj.Blog
select b
).ToList();
var blogsWithGivenTag =
from blog in db.BlogPosts
where blog.BlogTags.Any(bt => bt.Tag.Name == tagName)
select blog;
Read about performing inner joins with LINQ.
You can put the blogs in a dictionary, group the junctions on the blog id, and loop through the groups:
var blogDict = blogs.ToDictionary(b => b.Id);
foreach(var group in tagJunk.GroupBy(j => j.Fk_Blog_Id)) {
if (blogDict.ContainsKey(group.Key)) {
var blog = blogDict[group.Key];
foreach (var junction in group) {
// here you have the blog and the junction
}
}
}
This is also nested loops, but for each blog you only loop through the junctions that actually belong to that blog, instead of all junctions.

Join/Where with LINQ and Lambda

I'm having trouble with a query written in LINQ and Lambda. So far, I'm getting a lot of errors here's my code:
int id = 1;
var query = database.Posts.Join(database.Post_Metas,
post => database.Posts.Where(x => x.ID == id),
meta => database.Post_Metas.Where(x => x.Post_ID == id),
(post, meta) => new { Post = post, Meta = meta });
I'm not sure if this query is correct.
I find that if you're familiar with SQL syntax, using the LINQ query syntax is much clearer, more natural, and makes it easier to spot errors:
var id = 1;
var query =
from post in database.Posts
join meta in database.Post_Metas on post.ID equals meta.Post_ID
where post.ID == id
select new { Post = post, Meta = meta };
If you're really stuck on using lambdas though, your syntax is quite a bit off. Here's the same query, using the LINQ extension methods:
var id = 1;
var query = database.Posts // your starting point - table in the "from" statement
.Join(database.Post_Metas, // the source table of the inner join
post => post.ID, // Select the primary key (the first part of the "on" clause in an sql "join" statement)
meta => meta.Post_ID, // Select the foreign key (the second part of the "on" clause)
(post, meta) => new { Post = post, Meta = meta }) // selection
.Where(postAndMeta => postAndMeta.Post.ID == id); // where statement
You could go two ways with this. Using LINQPad (invaluable if you're new to LINQ) and a dummy database, I built the following queries:
Posts.Join(
Post_metas,
post => post.Post_id,
meta => meta.Post_id,
(post, meta) => new { Post = post, Meta = meta }
)
or
from p in Posts
join pm in Post_metas on p.Post_id equals pm.Post_id
select new { Post = p, Meta = pm }
In this particular case, I think the LINQ syntax is cleaner (I change between the two depending upon which is easiest to read).
The thing I'd like to point out though is that if you have appropriate foreign keys in your database, (between post and post_meta) then you probably don't need an explicit join unless you're trying to load a large number of records. Your example seems to indicate that you are trying to load a single post and its metadata. Assuming that there are many post_meta records for each post, then you could do the following:
var post = Posts.Single(p => p.ID == 1);
var metas = post.Post_metas.ToList();
If you want to avoid the n+1 problem, then you can explicitly tell LINQ to SQL to load all of the related items in one go (although this may be an advanced topic for when you're more familiar with L2S). The example below says "when you load a Post, also load all of its records associated with it via the foreign key represented by the 'Post_metas' property":
var dataLoadOptions = new DataLoadOptions();
dataLoadOptions.LoadWith<Post>(p => p.Post_metas);
var dataContext = new MyDataContext();
dataContext.LoadOptions = dataLoadOptions;
var post = Posts.Single(p => p.ID == 1); // Post_metas loaded automagically
It is possible to make many LoadWith calls on a single set of DataLoadOptions for the same type, or many different types. If you do this lots though, you might just want to consider caching.
Daniel has a good explanation of the syntax relationships, but I put this document together for my team in order to make it a little simpler for them to understand. Hope this helps someone
Your key selectors are incorrect. They should take an object of the type of the table in question and return the key to use in the join. I think you mean this:
var query = database.Posts.Join(database.Post_Metas,
post => post.ID,
meta => meta.Post_ID,
(post, meta) => new { Post = post, Meta = meta });
You can apply the where clause afterwards, not as part of the key selector.
Posting because when I started LINQ + EntityFramework, I stared at these examples for a day.
If you are using EntityFramework, and you have a navigation property named Meta on your Post model object set up, this is dirt easy. If you're using entity and don't have that navigation property, what are you waiting for?
database
.Posts
.Where(post => post.ID == id)
.Select(post => new { post, post.Meta });
If you're doing code first, you'd set up the property thusly:
class Post {
[Key]
public int ID {get; set}
public int MetaID { get; set; }
public virtual Meta Meta {get; set;}
}
I've done something like this;
var certificationClass = _db.INDIVIDUALLICENSEs
.Join(_db.INDLICENSECLAsses,
IL => IL.LICENSE_CLASS,
ILC => ILC.NAME,
(IL, ILC) => new { INDIVIDUALLICENSE = IL, INDLICENSECLAsse = ILC })
.Where(o =>
o.INDIVIDUALLICENSE.GLOBALENTITYID == "ABC" &&
o.INDIVIDUALLICENSE.LICENSE_TYPE == "ABC")
.Select(t => new
{
value = t.PSP_INDLICENSECLAsse.ID,
name = t.PSP_INDIVIDUALLICENSE.LICENSE_CLASS,
})
.OrderBy(x => x.name);
It could be something like
var myvar = from a in context.MyEntity
join b in context.MyEntity2 on a.key equals b.key
select new { prop1 = a.prop1, prop2= b.prop1};
This linq query Should work for you. It will get all the posts that have post meta.
var query = database.Posts.Join(database.Post_Metas,
post => post.postId, // Primary Key
meta => meat.postId, // Foreign Key
(post, meta) => new { Post = post, Meta = meta });
Equivalent SQL Query
Select * FROM Posts P
INNER JOIN Post_Metas pm ON pm.postId=p.postId
Query Syntax for LINQ Join
var productOrderQuery = from product in Product.Setup()//outer sequence
join order in OrderDetails.Setup()//inner sequence
on product.Id equals order.ProductId //key selector
select new//result selector
{
OrderId = order.Id,
ProductId = product.Id,
PurchaseDate = order.PurchaseDate,
ProductName = product.Name,
ProductPrice = product.Price
};
Method Syntax for LINQ Join
var productOrderMethod = Product.Setup().//outer sequence
Join(OrderDetails.Setup(), //inner sequence
product => product.Id//key selector
,order=> order.ProductId //key selector
,(product,order)=> //projection result
new
{
OrderId = order.Id,
ProductId = product.Id,
PurchaseDate = order.PurchaseDate,
ProductName = product.Name,
ProductPrice = product.Price
}
);
Product.cs for reference
class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public static IEnumerable<Product> Setup()
{
return new List<Product>()
{
new Product(){Id=1, Name="Bike", Price=30.33M },
new Product(){Id=2, Name="Car", Price=50.33M },
new Product(){Id=3, Name="Bus", Price=60.33M }
};
}
}
OrderDetails.cs class for reference
class OrderDetails
{
public int Id { get; set; }
public virtual int ProductId { get; set; }
public DateTime PurchaseDate { get; set; }
public static IEnumerable<OrderDetails> Setup()
{
return new List<OrderDetails>()
{
new OrderDetails(){Id=1, ProductId=1, PurchaseDate= DateTime.Now },
new OrderDetails(){Id=2, ProductId=1, PurchaseDate=DateTime.Now.AddDays(-1) },
new OrderDetails(){Id=3, ProductId=2, PurchaseDate=DateTime.Now.AddDays(-2) }
};
}
}
1 equals 1 two different table join
var query = from post in database.Posts
join meta in database.Post_Metas on 1 equals 1
where post.ID == id
select new { Post = post, Meta = meta };

Categories