I have a NoteBrief
public int Id { get; set; }
public string Title { get; set; }
public DateTime Created { get; set; }
public int ParentNoteId { get; set; }
Data looks something like
1 Title1 03/31/1987 1
2 Title1 03/31/1988 1
3 Title3 01/01/2000 3
4 Title4 01/01/2001 4
5 Title4 01/01/2005 4
I want to do:
SELECT t1.*
FROM Notes AS t1 LEFT JOIN Notes AS t2
ON (t1.ParentNoteId = t2.ParentNoteId AND t1.Created < t2.Created)
WHERE t2.Created IS NULL;
Right now i have:
public IQueryable<NoteBrief> GetNotes()
{
return _ctx.Notes.Select(r => new NoteBrief
{
Id = r.Id,
Title = r.Title,
Created = r.Created,
ParentNoteId = r.ParentNoteId,
});
}
I'm happy with this, but really don't need the older revisions of a parentNoteId, just need the one that was created last so i can link to it.
I've read many examples, some of which use FirstOrDefault and some that use max. Everytime i try to implement an example though, it doesn't work for me.
Entity Framework creating IQuerable of the most recent
This is what finally worked for me:
return from e in _ctx.Notes
group e by e.ParentNoteId into g
select g.OrderByDescending(e => e.Created).FirstOrDefault() into r
select new NoteBrief
{
Id = r.Id,
Title = r.Title,
Created = r.Created,
ParentNoteId = r.ParentNoteId,
};
Also edited my original post with correct query i was going for.
Thanks.
Try following
return _ctx.Notes.Select(r => new NoteBrief
{
Id = r.Id,
Title = r.Title,
Created = r.Created,
ParentNoteId = r.ParentNoteId,
}).OrderBy(x=>x.Created).GroupBy(x=>new {Id=x.Id, Title=x.Title}).Select(x=>x.First()).AsQueryable();
}
Related
In the code given below i want to join all the three table i get the data by joining the table but while displaying the data only the data of CK_Model is displayed. Please help
public List<CK_Model> GetDetails()
{
try
{
using (var entities = new MobileStore2020Entities())
{
var details = from a in entities.CK_Model
join b in entities.CK_Brand
on a.BrandID equals b.BrandID
join c in entities.CK_Stock
on a.ModelID equals c.ModelID
select new
{
ModelID = a.ModelID,
ModelName = a.ModelName
};
return details.ToList();
Thank You.
If I understand correctly you want to return data from all 3 tables by accessing them through your context. If you want to do this you have change your method's return type. For example create a new class with all 3 item types
public class DetailsItemType
{
public CK_Model Model{ get; set; }
public CK_Brand Brand { get; set; }
public CK_Stock Stock { get; set; }
}
Then change your method's return type to DetailsItemType and you'll have something like the following
public List<DetailsItemType> GetDetails()
{
using (var entities = new MobileStore2020Entities())
{
var details = from a in entities.CK_Model
join b in entities.CK_Brand
on a.BrandID equals b.BrandID
join c in entities.CK_Stock
on a.ModelID equals c.ModelID
select new DetailsItemType
{
Model= a,
Brand = b,
Stock = c
};
return details.ToList();
}
}
Now every time you call GetDetails() you can access all 3 tables. For example
var details = GetDetails();
var model = details.Model;
var brand = details.Brand;
var stock = details.Brand;
In Entity Framework, I would like to get one object which includes a list, but list gets only first record.
I have 2 objects Sale and Profile, they are different from database objects, I create these objects in query like "select new Sale { }". Profile object contains Sale type list. When query executed, list gets just first record in database.
Sale Complex Object
public class Sale
{
public int Id { get; set; }
public string Header { get; set; }
public double Price { get; set; }
}
Profile Complex Object
public class Profile
{
public int Id { get; set; }
public string Name { get; set; }
public List<Sale> SalesList { get; set; }
}
I use left join because it should insert this object to list, if next object is null.
Query Here
Profile profile = (from u in db.USER
join s in db.SALE on u.ID equals s.USER_ID into saleleft
from salej in saleleft.DefaultIfEmpty()
where u.ID == _userId
select new Profile
{
Id = u.ID,
Name = u.NAME,
SalesList= new List<Sale>()
{
salej != null ? new Sale
{
Id=postj.ID,
Header=salej.HEADER,
Price=salej.PRICE
} : null
}.ToList()
}).FirstOrDefault();
I guess this can be about FirstOrDefault() method. Hence I think it should get all records to SalesList. How can I get all records to list? Any idea?
Thanks in advance.
I think you need to use group here. Could you try this and let me know if it works?
// didn't test the code
Profile profile = (from u in db.USER
join s in db.SALE on u.ID equals s.USER_ID into saleleft
where u.ID == _userId
from salej in saleleft.DefaultIfEmpty()
group salej by new { u.ID, u.NAME } into g
select new Profile
{
Id = g.Key.ID,
Name = g.Key.NAME,
SalesList = g.Select( x => new Sale { Id = postj.ID, Header = x.HEADER, Price = x.PRICE }).ToList()
}).FirstOrDefault();
Btw, what is postj?
I have an Entity Framework model in which there is a "Customers" and a "CustomerPhones" table. A customer can have multiple phone numbers so the "Customer" entity has a collection of "Phone". I can query the model with no problem :
using (CustomerEntities context = new CustomerEntities())
{
Customer customer = context.Customers.FirstOrDefault();
CustomerPhone phone = customer.Phones.FirstOrDefault();
MessageBox.Show(customer.Name + " " + phone.Number);
}
The model is too complex for what I need to do (even though my example is basic) so I'm trying to boil it down to simpler POCOs. Here are the 2 simple classes :
public class SimplePhone
{
public int Id { get; set; }
public string Number { get; set; }
}
public class SimpleCustomer
{
public int Id { get; set; }
public string Name { get; set; }
//Phones is a list because a single Customer can have multiple phone numbers
public List<SimplePhone> Phones { get; set; }
}
I can populate the simple properties of the object using the "Select" method of "IQueryable" :
using (CustomerEntities context = new CustomerEntities())
{
IQueryable<SimpleCustomer> customers = context.Customers.Select(
c => new SimpleCustomer
{
Id = c.Id,
Name = c.Name
}
);
SimpleCustomer customer = customers.FirstOrDefault();
MessageBox.Show(customer.Name);
}
So my question is pretty simple : how can I populate the "Phones" property which is a list?
using (CustomerEntities context = new CustomerEntities())
{
IQueryable<SimpleCustomer> customers = context.Customers.Select(
c => new SimpleCustomer
{
Id = c.Id,
Name = c.Name
Phones = ///????
}
);
SimpleCustomer customer = customers.FirstOrDefault();
SimplePhone phone = customer.Phones.FirstOrDefault();
MessageBox.Show(customer.Name + " " + phone.Number);
}
Let me know if I'm unclear and/or you need more details.
Thanks!
I'm not sure if there isn't something more to your question, but as far as I understand, you can just call ToList and it will be materialized as a list:
IQueryable<SimpleCustomer> customers =
context.Customers.Select(c => new SimpleCustomer
{
Id = c.Id,
Name = c.Name,
Phones = c.Phones.Select(p => new SimplePhone
{
Id = p.Id, // Unless you want the custom Id, i.e. c.Id
Number = p.Number
}).ToList();
});
how can I retrieve data from junction table in Code first approach.i know i can add data like this.
Movie.Tag.Add(item)
but want to know how to get back those data in the junction table
This gives you all rows in the junction table - each row is represented as an anonymous object with the two Ids of the row as properties:
var junctionTableDataList = (from m in context.Movies
from t in m.Tags
select new
{
MovieId = m.MovieId,
TagId = t.TagId
}).ToList();
You can add a where clause before the select if you want to limit the result to a specific or a few movies.
Edit
The same with extension methods and lambda expressions would look like this:
var junctionTableDataList = context.Movies
.SelectMany(m => m.Tags.Select(t => new
{
MovieId = m.MovieId,
TagId = t.TagId
}))
.ToList();
Edit 2
If you want return the data from a method you can create a litte helper type and return a list of those "named" objects instead of anonymous objects:
public class JunctionData
{
public int MovieId { get; set; }
public int TagId { get; set; }
}
List<JunctionData> junctionTableDataList
= (from m in context.Movies
from t in m.Tags
select new JunctionData
{
MovieId = m.MovieId,
TagId = t.TagId
}).ToList();
Or ...Select(t => new JunctionData... for the extension method syntax.
Say I had a class:
public class Post
{
public int PostId { get; set; }
public string Topic { get; set; }
public int UserId { get; set; }
[StringLength(5000)]
public string Body { get; set; }
public DateTime DateCreated { get; set; }
public string Name { get; set; }
public int Votes { get; set; }
}
And for each post, a user could input a topic. for example, if the topics were "Red" "Green" "Blue" and "Yellow", how could I create a list based on how many times those were used?
An example output:
Red | 70
Blue | 60
Green | 40
Yellow| 35
EDIT: How come this doesn't work and gives me an error where I cannot implicitly convert the type?
public List<string> GetPopularTopics(int count)
{
var posts = from p in db.Posts
group p by p.Topic into myGroup
select new
{
Topic = myGroup.Key,
Count = myGroup.Count()
};
return posts.ToList();
}
EDIT 2:
So I tried your solution out Dustin, and I'm getting an error. This is what I used:
public IEnumerable<IGrouping<string,int>> GetPosts()
{
var posts = from p in db.Posts
group p by p.Topic into topicCounts
select new
{
Topic = topicCounts.Key,
Count = topicCounts.Count()
};
return posts.ToList();
}
This is giving me an error under posts.ToList():
Cannot implicitly convert type 'System.Collections.Generic.List' to 'System.Collections.Generic.IEnumerable>'. An explicit conversion exists (are you missing a cast?)
To create the grouping you create an anonymous type such as:
var posts = from p in context.Posts
group p by p.Topic into topicCounts
select new
{
Topic = topicCounts.Key,
Count = topicCounts.Count()
};
Then to work with the date, lets say iterate over it:
foreach(var p in posts)
{
Response.Write(String.Format("{0} - {1}", p.Topic, p.Count));
}
You must create a new type if you do a projection and return it form method!
public class MyCounts
{
public string Topic { get; set; }
public int Count { get; set; }
}
public List<MyCounts> GetPopularTopics(int count)
{
var posts = from p in db.Posts
group p by p.Topic into myGroup
select new MyCounts
{
Topic = myGroup.Key,
Count = myGroup.Count()
};
return posts.ToList();
}
The problem is that you need to use an non anonymous type for your return value.
This query creates an IEnumerable of anonymous types.
var posts = from p in context.Posts
group p by p.Topic into topicCounts
select new
{
Topic = topicCounts.Key,
Count = topicCounts.Count()
};
It's the select new statement that creates the anonymous objects.
What you need to do is to create something that is non anonymous - an object that can be shared within and outside this method.
Like this:
public IEnumerable<TopicAndCount> GetPosts()
{
var posts = from p in context.Posts
group p by p.Topic into topicCounts
select new TopicAndCount
{
Topic = topicCounts.Key,
Count = topicCounts.Count()
};
}
Note the select new TopicAndCount statement and the return value of the enclosing method.
That will solve your problem.