简体   繁体   中英

ASP.NET C# MVC Entity Framework

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM