ASP.NET C# MVC 实体框架

Posted

技术标签:

【中文标题】ASP.NET C# MVC 实体框架【英文标题】:ASP.NET C# MVC Entity Framework 【发布时间】:2020-05-26 22:45:42 【问题描述】:

我正在学习 ASP.NET MVC,但我一直坚持使用实体框架创建复杂的 SQL - 它并不复杂,但它可能会变得复杂。

我的常规 ASP.NET C# 网络表单如下所示,我想将其转换为 ASP.NET MVC 并使用 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
            
        
    

我的问题是如何使用实体框架实现这种类型的 SQL。

我已经使用数据库优先的方法创建了实体并设置了DbContext

private NewsEntities db = new NewsEntities();

我有两个数据库表:News & NewsImage 单个新闻可以有多个新闻图像(1-N)

我尝试过实现这样的目标:

新闻类

public class NewsClass
    
        public News NewsDetails  get; set; 
        public NewsImage NewsImages  get; set; 
    

型号:新闻

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; 

模型: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; 

控制器:

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 ;

从这里我被困住了...... 子查询上的“select top 1”,如何实现这个

越来越好... 现在我做了这样的事情:

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);

现在我需要将“newsImages”和“allNews”这两个对象合并到一个列表“newsList”中。

如何将查询 allNews 和 newsImages 的两个列表合并到一个列表中,如下所示:

select new NewsList

    NewsGuid = n.NewsGuid,
    Heading = n.Heading,
    FileName = ni.FileName
).Take(sqlTop).ToList<NewsList>();

【问题讨论】:

您是否创建了实体?设置你的 DbContext?这类信息属于问题。 Entity Framework 的全部意义在于您不再需要使用原始 SQL!不要尝试复制这种 1:1 - 使用实体框架方法 - 使用从数据库返回的对象及其导航属性! @marc_s thx,这就是我发布这个的原因,以避免经典的方式进入 EF 方式,但我坚持如何处理这个特定的任务。 查看我的回复 - 可以作为一个起点 - 如果您可以从原始 SQL 中解放出来,您应该会向您展示作为开发人员所获得的好处和巨大的生产力提升 .... EF 的这种方法比我原来的传统方法更快吗? 【参考方案1】:

Entity Framework(和其他 ORM)的主要好处是您不必再编写原始 SQL 来实现您的目标。 OR 映射器创建了一个很好用的对象结构,您可以使用它来进行查询。

在你的情况下 - 你会做类似的事情:

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
    

【讨论】:

var query = db.News.Include(n => n.NewsImage);这会引发错误。 NewsImage 不是来自 News 表。它来自单独的表 NewsImage,其中有一个名为 NewsGuid 的列,它也将在 News 表中,所以我进行左连接。因为一条新闻会有超过 1 个图像,所以我只抓取第一个作为列表视图。对于详细视图,我将选择所有图像。这就是为什么我有 TOP 1 文件名 我在原来的问题中添加了更多内容......请。检查 btw @marc_s if (DateTime.TryParse(date, out newsDate)) 抛出以下错误:无法从“out System.DateTime?”转换'out System.DateTime' @user2160310:你还没有发布所有相关的细节 - 例如。我不知道NewsDetails 是什么样子的——这些字段是什么以及它们叫什么——所以我不能真正提供100% 准确和正确的实现;但是这篇文章应该给你一个想法和一个起点 .@user2160310:添加了一行代码从导航属性中获取第一个“NewsImage”,按FileOrder排序 我已经更新了 News 和 NewsImage 类(数据库表 EF 创建了这两个)

以上是关于ASP.NET C# MVC 实体框架的主要内容,如果未能解决你的问题,请参考以下文章

使用带有实体框架代码优先和 ASP.NET MVC 3 和 mvc miniprofiler 的 SQL Server CE 时出现问题

表单身份验证、ASP.NET MVC 和 WCF RESTful 服务

MVC Contrib 是不是兑现了提高 ASP.NET MVC 生产力的承诺

在 WPF、Silverlight 和 ASP.NET 之间共享一个公共 DAL

如何在 Asp.Net 5 (MVC 6) 中使用实体框架 6.x

asp.net mvc 模型与实体框架模型