I am learning ASP.NET MVC and I'm stuck at creating complex SQL using Entity Framework - it's not that complex, but it can get complex.
My regular ASP.NET C# webform looks like this, and I want to convert that to ASP.NET MVC and with Entity Framework.
string date = Request.QueryString["date"] ?? "";
string strWhere = "";
string sqlTop = "20";
DateTime temp;
if (DateTime.TryParse(date, out temp))
{
strWhere = "WHERE CAST(NewsDate AS date)='" + temp.ToString("yyyy-MM-dd") + "'";
sqlTop = "50";
}
using (SqlConnection con = new SqlConnection(WebConfigurationManager.ConnectionStrings["NewsDB"].ConnectionString))
{
con.Open();
string selectSql = @"SELECT TOP " + sqlTop + @" *
, (SELECT TOP 1 FileName
FROM NewsImage
WHERE NewsGuid = N.NewsGuid
ORDER BY FileOrder ASC) AS FileName
FROM News N " + strWhere + @"
ORDER BY N.NewsDate DESC";
using (SqlCommand selectCmd = new SqlCommand(selectSql, con))
{
using (SqlDataReader selectDr = selectCmd.ExecuteReader())
{
while (selectDr.Read())
{
//My Output logic goes here
}
}
}
}
My question is how do I achieve this type of SQL using Entity Framework.
I have created the entities and setup the DbContext
using a database-first approach.
private NewsEntities db = new NewsEntities();
I have two database tables: News & NewsImage Single news can have multiple newsimages (1-N)
I have tried achieve something like this:
NewsClass
public class NewsClass
{
public News NewsDetails { get; set; }
public NewsImage NewsImages { get; set; }
}
Model: News
public partial class News
{
public int Id { get; set; }
public System.Guid NewsGuid { get; set; }
public string Heading { get; set; }
public string Text { get; set; }
public string Author { get; set; }
public System.DateTime NewsDate { get; set; }
}
Model: NewsImage
public partial class NewsImage
{
public int Id { get; set; }
public System.Guid NewsGuid { get; set; }
public string FileName { get; set; }
public int FileOrder { get; set; }
}
Controller:
var newsList = from n in news
join img in newsImages on n.NewsGuid equals img.NewsGuid into table1
from img in table1.DefaultIfEmpty()
select new NewsClass { NewsDetails = n, NewsImage = img };
from here I am stuck... the "select top 1" on subquery, how to achieve this
Getting better... Now I have done something like this:
var newsImages = db.NewsImages.OrderBy(n => n.NewsGuid).OrderBy(n => n.FileOrder).Where(n => n.FileOrder == 10);
var allNews = db.News.OrderByDescending(n => n.NewsDate).Take(sqlTop);
if (validDate)
allNews = allNews.Where(n => n.NewsDate.Year == newsDate.Year && n.NewsDate.Month == newsDate.Month && n.NewsDate.Day == newsDate.Day);
Now I need to combine these two objects "newsImages" and "allNews" to one list "newsList".
How do I combine the two lists queries allNews and newsImages into one list like this:
select new NewsList
{
NewsGuid = n.NewsGuid,
Heading = n.Heading,
FileName = ni.FileName
}).Take(sqlTop).ToList<NewsList>();
The main benefit of Entity Framework (and other ORM) is that you don't have to write raw SQL anymore to achieve you goals. The OR mapper creates a nicely usable object structure that you can use to do your querying.
In your case - you'd be doing something like :
string date = Request.QueryString["date"] ?? "";
int sqlTop = 20;
DateTime? newsDate = null;
if (DateTime.TryParse(date, out DateTime temp))
{
newsDate = temp;
sqlTop = 50;
}
using (NewsEntities db = new NewsEntities())
{
// grab the "NewsClass" entries - include the "NewsDetails" and
// "NewsImage" navigation property
var query = db.NewsClass
.Include(n => n.NewsDetails);
.Include(n => n.NewsImage);
// if you have a valid date - use that to refine the query
if (newsDate.HasValue)
{
query = query.Where(n => n.NewsDetails.NewsDate == newsDate.Value);
}
// order by NewsDate, and select only "sqlTop" entries
query = query.OrderByDescending(n => n.NewsDetails.NewsDate
.Take(sqlTop);
// now you can iterate over the "News" objects returned from the query
foreach(News n in query)
{
// get the first image from navigation property
var firstImage = n.NewsImage
.OrderBy(img => img.FileOrder)
.FirstOrDefault();
// do whatever you want with your news - output what you need
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.