我当前的问题(可能)不一定与MVC 6直接相关,但是如何使用数据库实际上是有效的,因此在这个问题上的任何帮助/建议都将不胜感激。
为了这个问题,我们假设我们有一个非常简单的数据库,其中包含以下表格(C#类)[我们正在使用Entity Framework来处理数据库]:
public class ShoppingUser
{
public int Id { get; set; }
public string UserName { get; set; }
public ICollection<ShoppingItem> Items { get; set; }
}
public class ShoppingItem
{
public int Id { get; set; }
public string Quantity { get; set; }
public string Text { get; set; }
public bool ToRemove { get; set; }//if item has been bought, it can be removed from the shopping list
}
此演示将针对超级简单的购物清单应用,其中在系统中注册的用户(ShoppingUser
)可以具有ShoppingItem
的列表,其中用户可以决定什么是文本项目(例如面包,黄油,西红柿......)以及数量(3件,5公斤,......简单的字符串)
之后在我的ASP.NET核心应用程序中,我定义了一个与数据库通信的存储库,并且可以访问ShoppingItem
类(因为我们只对当前登录用户的购物项感兴趣)。
我们可以在这里使用的一些方法示例:
public IEnumerable<ShoppingItem> ReturnUserItems(string sUsername)
{
if (string.IsNullOrWhiteSpace(sUsername))
return null;
var result = _context.ShoppingUsers.Include(n => n.Items).Where(n => n.UserName == sUsername).FirstOrDefault();
if (result != null)
return result.Items;
else
return null;
}
最后,我们为JsonResult
,GET
,POST
,...提供了DELETE
的API控制器,用于客户端AngularJs App和我们的服务器端逻辑。
GET
方法示例:
// GET: /<controller>/
[HttpGet("")]
public JsonResult Get(string sUserName)
{
try
{
var results = _repository.ReturnUserItems(User.Identity.Name);
if (results != null)
{
var result = Mapper.Map<IEnumerable<ShoppingItemViewModel>>(results);
return Json(result);
}
Response.StatusCode = (int)HttpStatusCode.OK;
}
catch (Exception ex)
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(new { Message = ex.Message });
}
return null;
}
这是棘手的部分(至少对我而言)。从我学到的视频教程中,我不应该(或几乎从不)将我的真实数据库模型暴露给网站(我想这是出于安全原因)。由于这个原因(从我上面的GET
方法可见)我已经声明我的ShoppingItemViewModel
只包含我想要向用户公开的属性(例如意味着我的项目的Id不可见)。
这就是它的样子:
public class ShoppingItemViewModel
{
public string Quantity { get; set; }
[Required]
public string Text { get; set; }
[Required]
public bool ToRemove { get; set; }//if item has been bought, it can be removed from the shopping list
}
对于来自我的AngularJS App的通信,我使用简单的$http.get
和$http.post
调用来检索/发布更新的数据。
最后一个问题:
我的问题是,如果用户决定从购物清单中删除某个商品,或者决定更改文字/数量的内容(这意味着最初在数据库中西红柿 - 5公斤< / strong>但他设法只购买2公斤,因此将数量改为西红柿 - 3公斤),该应用程序如何理解哪些元素实际已被更改以及如何更改?我遇到的问题是,我们不再公开项目的数据库ID。
如果我正在编写桌面应用程序,我不必创建此子视图(ShoppingItemViewModel
),我的EntityFramework足够智能,可以检查&amp;更新我的数据库中的所有更改。不幸的是,在这种情况下,我不明白这是如何实现的。
当我考虑它时,我提到了以下内容:在ShoppingItem
和ShoppingItemViewModel
:public string sCustomKey {get; set; }
中添加新属性,该属性将作为每个项目的唯一键。这样,我们不再需要公开我们的数据库ID,但我们暴露了'假的'。
第二个问题: 我的情况是我的解决方案是准确的,更新数据库中项目的最佳方法是什么?我能想到的唯一方法是遍历数据库中的所有项目并手动检查更改?
我想到的例子:
//IEnumerable<ShoppingItem> would be re-mapped result of ShoppingItemViewModel we have received back from the website
public void UpdateValues(IEnumerable<ShoppingItem> items, string sUserName)
{
//retrieves list of shopping items for specified customer
var allItems = _context.ShoppingUsers
.Include(n => n.Items)
.FirstOrDefault(n => n.UserName == sUserName);
//updates the values
foreach (var sItem in items)
{
var updatedItem = allItems.Items.FirstOrDefault(n => n.Text == sItem.sCustomKey);
if (updatedItem == null)
{
//create new item
var newItem = new ShoppingItem();
newItem.Text = sItem.Text;
newItem.ToRemove = sItem.ToRemove;
allItems.Items.Add(newItem);
}
else
updatedItem.ToRemove = sItem.ToRemove;
}
_context.SaveChanges();
}
但这种做法对我来说似乎不对。
关于这些问题的任何帮助都将不胜感激,因为我仍在学习如何使用ASP.NET Core和Web项目。
答案 0 :(得分:1)
在第一个问题中,在ViewModel中公开项ID很好。在您的域层中,您可以添加那些ID存在/有效项的验证逻辑。 或者,您可以为项目/产品使用Guid,因为可以很容易地预测ID(int)。
就更新项目而言,您不应使用&#34;用户名&#34;作为(购物车的)标识符,因为可以由调用客户端预测/更改。你可以使用Guid持久化(到Db)或 在记忆中。如果此Guid属于此用户名/ emailAddress,您也可以添加验证。因此,更新购物车中的商品,如果可行,请考虑一次添加/删除一个商品 而不是发送项目列表。
答案 1 :(得分:0)
我认为你误会了什么。
这是棘手的部分(至少对我而言)。从我学到的视频教程中,我不应该(或几乎从不)将我的真实数据库模型暴露给网站(我想这是出于安全原因)。由于这个原因(从我上面的GET方法可见)我已经声明了我的ShoppingItemViewModel,它只包含我想要向用户公开的属性(例如意味着我的项目的Id不可见)。
ViewModel&lt; =&gt;域模型&lt; =&gt; ReadModel(数据库模型)
重点是您不应将ReadModel(数据库模型)用作表示层(MVC)中的ViewModel。这三种模型都具有同一性。