.NET Core 中的数据库视图
DB view in .NET Core
我从为 CRUD 设置的数据库中注入了一个 table。
ID EID Task entrydate Level
1 1 Demographics 2017-02-23 2
2 0 Demographics 2017-02-23 2
3 1 Progress Notes 2017-03-06 2
4 1 Demographics 2017-03-06 3
5 1 Assessments 2017-03-06 3
6 1 Assessments 2017-01-25 1
但是,为了以对客户有意义的方式显示数据,我需要按条目日期在列中列出级别数据。
ID EId Task 25 Jan 2017 23 Feb 2017 06 Mar 2017
1 1 Demographics NULL 2 NULL
2 0 Demographics NULL 2 NULL
3 1 Progress Notes NULL NULL 2
4 1 Demographics NULL NULL 3
5 1 Assessments NULL NULL 3
6 1 Assessments 1 NULL NULL
我一直致力于在控制器和视图中使用 LINQ 以在视图中创建正确的 table。
控制器:
public IActionResult Index(int id)
{
HttpContext.Session.SetInt32("EmployeeID", id);
var model = db.EmployeeTask
.Where(h => h.EmployeeId == id)
.OrderByDescending(h => h.Entrydate);
return View(model);
}
查看页面:
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.KeyTask)
</th>
@foreach (var group in Model.GroupBy(item => item.Entrydate))
{
<th>
@group.Key.Date
</th>
}
<th></th>
</tr>
</thead>
<tbody>
@foreach (var group in Model.GroupBy(item => item.KeyTask)) {
<tr>
<td>
@group.Key
</td>
@foreach (var item in group)
{
<td>
@Html.DisplayFor(modelItem => item.Acceptable)
</td>
}
</tr>
}
</tbody>
</table>
根据我的结果,我快到了。
View from MVC
我遗漏了一些东西,因为接受的数据与 entrydate 列不匹配。我是在正确的道路上,还是已经达到了 LINQ 的极限并且需要尝试另一种方法?
经过大量搜索、阅读、反复试验,我找到了实现此功能的方法。
首先,我意识到 LINQ 表达式不是我需要的方式。我需要单独构建行。由于数据具有动态列,因此 DBSet 不起作用。所以我在 SQL;
中构建了一个 Pivot 查询
DECLARE @cols NVARCHAR (MAX),
@StartDate date = '03/01/2017',
@EndDate date = '03/20/2017',
@Id nvarchar(10) = 1
SELECT @cols = COALESCE (@cols + ',[' + CONVERT(NVARCHAR, entrydate, 106) +
']',
'[' + CONVERT(NVARCHAR, entrydate, 106) + ']')
FROM (SELECT DISTINCT entrydate
FROM EmployeeTask
WHERE entrydate >= @StartDate AND entrydate <= @EndDate
AND EmployeeId = @Id) PV
ORDER BY entrydate DESC
DECLARE @query NVARCHAR(MAX)
SET @query = '
SELECT * FROM (SELECT KeyTask, acceptable, entrydate
FROM EmployeeTask
WHERE EmployeeId = ('+ @Id +')
Group by KeyTask, acceptable, entrydate) x
PIVOT (SUM(acceptable) FOR entrydate IN (' + @cols + ')) p
'
EXEC SP_EXECUTESQL @query
这给了我想要显示的 table,但是如何让它在 MVC 6 中显示?
首先,我找到了 this SO post,Petr Vobornik 的回答正是我所需要的。我不得不修改它并将其添加到我的控制器中:
private static List<Dictionary<string, object>> LoadData(string sqlSelect,
params object[] sqlParameters)
{
var table = new List<Dictionary<string, object>>();
using (var ctx = new DBContext())
{
ctx.Database.GetDbConnection();
ctx.Database.OpenConnection();
using (var cmd = ctx.Database.GetDbConnection().CreateCommand())
{
cmd.CommandText = sqlSelect;
foreach (var param in sqlParameters)
cmd.Parameters.Add(param);
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var row = new Dictionary<string, object>();
for (int i = 0; i < reader.FieldCount; i++)
row[reader.GetName(i)] = reader[i];
table.Add(row);
}
if (table == null)
{
var row = new Dictionary<string, object>();
for (int i = 0; i < 1; i++)
row[reader.GetName(i)] = "None";
table.Add(row);
}
}
}
}
return table;
}
if语句用于添加一个空行,因此列表仍然生成,但它不包含任何内容。这样,如果查询 returns 什么都没有,仍然可以加载一个空视图(见下面的视图)。
我在控制器中添加了 SQL 连接:
public IActionResult Index(int id, string datestart, string dateend)
{
HttpContext.Session.SetInt32("EmployeeID", id);
if(datestart == null)
{
var setdate = DateTime.Now;
datestart = setdate.AddMonths(-3).ToString();
}
if(dateend == null)
{
dateend = DateTime.Now.ToString();
}
var start = new SqlParameter("@StartDate", datestart);
var end = new SqlParameter("@EndDate", dateend);
var EmpId = new SqlParameter("@Id", id);
var tasks = LoadData("EXECUTE dbo.TaskView @StartDate, @EndDate,
@Id",start,end,EmpId);
ViewBag.start = DateTime.Parse(datestart);
ViewBag.end = DateTime.Parse(dateend);
return View(tasks);
}
接下来,我修改了视图:
@model List<Dictionary<string, object>>
@{
ViewData["Title"] = "Employee Tasks";
}
<h2>Employee Tasks</h2>
<div class="panel panel-default">
<div class="panel-heading">Search by dates</div>
<div class="panel-body">
<form asp-controller="EmployeeTasks" asp-action="Index">
<label>Start Date</label>
<input type="date" name="datestart" id="start" value=@ViewBag.start
/>
<label>End Date</label>
<input type="date" name="dateend" id="end" value=@ViewBag.end />
<input type="submit" value="Search" />
</form>
</div>
</div>
<p>
<a asp-action="Create">Add New Employee Task</a>
</p>
@if (Model.FirstOrDefault() != null)
{
<table class="table table-bordered">
@foreach (var row in Model.FirstOrDefault())
{
<th>@row.Key</th>
}
@foreach (var row in Model)
{
<tr>
@foreach (var column in row)
{
<td>@column.Value</td>
}
</tr>
}
</table>
}
<div>
<a asp-controller="Employees" asp-action="Index">Back to Employee
Search</a>
</div>
最后的结果!
如果有人有更简单的方法,请post作为答案,这样我就可以尝试一下,但这在 .NET Core 1.1 中效果很好。
在 Asp.Net 核心代码优先方法中有一个更好的方法来处理这个问题,因为您只需要在 Sql 服务器中创建相应的视图,例如,
CREATE VIEW VIEWNAME AS SELECT ENTRYDATE,COL1,COL2 FROM TABLES GROUP BY ENTRYDATE
然后您只需在 Web 应用程序中创建一个与 VIEWNAME 同名的 ViewModel class,然后您需要在您的 dbcontext class
public DbQuery<VIEWNAME> VIEWNAME { get; set; }
现在不需要任何连接,因为您已经将所有连接放入您创建的数据库视图中,您只需从控制器调用此行来获取数据。
var data=dbContext.VIEWNAME.tolist();
就是这样....干杯
我从为 CRUD 设置的数据库中注入了一个 table。
ID EID Task entrydate Level
1 1 Demographics 2017-02-23 2
2 0 Demographics 2017-02-23 2
3 1 Progress Notes 2017-03-06 2
4 1 Demographics 2017-03-06 3
5 1 Assessments 2017-03-06 3
6 1 Assessments 2017-01-25 1
但是,为了以对客户有意义的方式显示数据,我需要按条目日期在列中列出级别数据。
ID EId Task 25 Jan 2017 23 Feb 2017 06 Mar 2017
1 1 Demographics NULL 2 NULL
2 0 Demographics NULL 2 NULL
3 1 Progress Notes NULL NULL 2
4 1 Demographics NULL NULL 3
5 1 Assessments NULL NULL 3
6 1 Assessments 1 NULL NULL
我一直致力于在控制器和视图中使用 LINQ 以在视图中创建正确的 table。
控制器:
public IActionResult Index(int id)
{
HttpContext.Session.SetInt32("EmployeeID", id);
var model = db.EmployeeTask
.Where(h => h.EmployeeId == id)
.OrderByDescending(h => h.Entrydate);
return View(model);
}
查看页面:
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.KeyTask)
</th>
@foreach (var group in Model.GroupBy(item => item.Entrydate))
{
<th>
@group.Key.Date
</th>
}
<th></th>
</tr>
</thead>
<tbody>
@foreach (var group in Model.GroupBy(item => item.KeyTask)) {
<tr>
<td>
@group.Key
</td>
@foreach (var item in group)
{
<td>
@Html.DisplayFor(modelItem => item.Acceptable)
</td>
}
</tr>
}
</tbody>
</table>
根据我的结果,我快到了。
View from MVC
我遗漏了一些东西,因为接受的数据与 entrydate 列不匹配。我是在正确的道路上,还是已经达到了 LINQ 的极限并且需要尝试另一种方法?
经过大量搜索、阅读、反复试验,我找到了实现此功能的方法。
首先,我意识到 LINQ 表达式不是我需要的方式。我需要单独构建行。由于数据具有动态列,因此 DBSet 不起作用。所以我在 SQL;
中构建了一个 Pivot 查询DECLARE @cols NVARCHAR (MAX),
@StartDate date = '03/01/2017',
@EndDate date = '03/20/2017',
@Id nvarchar(10) = 1
SELECT @cols = COALESCE (@cols + ',[' + CONVERT(NVARCHAR, entrydate, 106) +
']',
'[' + CONVERT(NVARCHAR, entrydate, 106) + ']')
FROM (SELECT DISTINCT entrydate
FROM EmployeeTask
WHERE entrydate >= @StartDate AND entrydate <= @EndDate
AND EmployeeId = @Id) PV
ORDER BY entrydate DESC
DECLARE @query NVARCHAR(MAX)
SET @query = '
SELECT * FROM (SELECT KeyTask, acceptable, entrydate
FROM EmployeeTask
WHERE EmployeeId = ('+ @Id +')
Group by KeyTask, acceptable, entrydate) x
PIVOT (SUM(acceptable) FOR entrydate IN (' + @cols + ')) p
'
EXEC SP_EXECUTESQL @query
这给了我想要显示的 table,但是如何让它在 MVC 6 中显示?
首先,我找到了 this SO post,Petr Vobornik 的回答正是我所需要的。我不得不修改它并将其添加到我的控制器中:
private static List<Dictionary<string, object>> LoadData(string sqlSelect,
params object[] sqlParameters)
{
var table = new List<Dictionary<string, object>>();
using (var ctx = new DBContext())
{
ctx.Database.GetDbConnection();
ctx.Database.OpenConnection();
using (var cmd = ctx.Database.GetDbConnection().CreateCommand())
{
cmd.CommandText = sqlSelect;
foreach (var param in sqlParameters)
cmd.Parameters.Add(param);
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var row = new Dictionary<string, object>();
for (int i = 0; i < reader.FieldCount; i++)
row[reader.GetName(i)] = reader[i];
table.Add(row);
}
if (table == null)
{
var row = new Dictionary<string, object>();
for (int i = 0; i < 1; i++)
row[reader.GetName(i)] = "None";
table.Add(row);
}
}
}
}
return table;
}
if语句用于添加一个空行,因此列表仍然生成,但它不包含任何内容。这样,如果查询 returns 什么都没有,仍然可以加载一个空视图(见下面的视图)。
我在控制器中添加了 SQL 连接:
public IActionResult Index(int id, string datestart, string dateend)
{
HttpContext.Session.SetInt32("EmployeeID", id);
if(datestart == null)
{
var setdate = DateTime.Now;
datestart = setdate.AddMonths(-3).ToString();
}
if(dateend == null)
{
dateend = DateTime.Now.ToString();
}
var start = new SqlParameter("@StartDate", datestart);
var end = new SqlParameter("@EndDate", dateend);
var EmpId = new SqlParameter("@Id", id);
var tasks = LoadData("EXECUTE dbo.TaskView @StartDate, @EndDate,
@Id",start,end,EmpId);
ViewBag.start = DateTime.Parse(datestart);
ViewBag.end = DateTime.Parse(dateend);
return View(tasks);
}
接下来,我修改了视图:
@model List<Dictionary<string, object>>
@{
ViewData["Title"] = "Employee Tasks";
}
<h2>Employee Tasks</h2>
<div class="panel panel-default">
<div class="panel-heading">Search by dates</div>
<div class="panel-body">
<form asp-controller="EmployeeTasks" asp-action="Index">
<label>Start Date</label>
<input type="date" name="datestart" id="start" value=@ViewBag.start
/>
<label>End Date</label>
<input type="date" name="dateend" id="end" value=@ViewBag.end />
<input type="submit" value="Search" />
</form>
</div>
</div>
<p>
<a asp-action="Create">Add New Employee Task</a>
</p>
@if (Model.FirstOrDefault() != null)
{
<table class="table table-bordered">
@foreach (var row in Model.FirstOrDefault())
{
<th>@row.Key</th>
}
@foreach (var row in Model)
{
<tr>
@foreach (var column in row)
{
<td>@column.Value</td>
}
</tr>
}
</table>
}
<div>
<a asp-controller="Employees" asp-action="Index">Back to Employee
Search</a>
</div>
最后的结果!
如果有人有更简单的方法,请post作为答案,这样我就可以尝试一下,但这在 .NET Core 1.1 中效果很好。
在 Asp.Net 核心代码优先方法中有一个更好的方法来处理这个问题,因为您只需要在 Sql 服务器中创建相应的视图,例如,
CREATE VIEW VIEWNAME AS SELECT ENTRYDATE,COL1,COL2 FROM TABLES GROUP BY ENTRYDATE
然后您只需在 Web 应用程序中创建一个与 VIEWNAME 同名的 ViewModel class,然后您需要在您的 dbcontext class
public DbQuery<VIEWNAME> VIEWNAME { get; set; }
现在不需要任何连接,因为您已经将所有连接放入您创建的数据库视图中,您只需从控制器调用此行来获取数据。
var data=dbContext.VIEWNAME.tolist();
就是这样....干杯