从网站

时间:2016-07-15 08:36:00

标签: asp.net asp.net-mvc database entity-framework asp.net-core

我当前的问题(可能)不一定与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;
    }

最后,我们为JsonResultGETPOST,...提供了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;更新我的数据库中的所有更改。不幸的是,在这种情况下,我不明白这是如何实现的。

当我考虑它时,我提到了以下内容:在ShoppingItemShoppingItemViewModelpublic 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项目。

2 个答案:

答案 0 :(得分:1)

  1. 在第一个问题中,在ViewModel中公开项ID很好。在您的域层中,您可以添加那些ID存在/有效项的验证逻辑。 或者,您可以为项目/产品使用Guid,因为可以很容易地预测ID(int)。

  2. 就更新项目而言,您不应使用&#34;用户名&#34;作为(购物车的)标识符,因为可以由调用客户端预测/更改。你可以使用Guid持久化(到Db)或 在记忆中。如果此Guid属于此用户名/ emailAddress,您也可以添加验证。因此,更新购物车中的商品,如果可行,请考虑一次添加/删除一个商品 而不是发送项目列表。

答案 1 :(得分:0)

我认为你误会了什么。

  

这是棘手的部分(至少对我而言)。从我学到的视频教程中,我不应该(或几乎从不)将我的真实数据库模型暴露给网站(我想这是出于安全原因)。由于这个原因(从我上面的GET方法可见)我已经声明了我的ShoppingItemViewModel,它只包含我想要向用户公开的属性(例如意味着我的项目的Id不可见)。

ViewModel&lt; =&gt;域模型&lt; =&gt; ReadModel(数据库模型)

重点是您不应将ReadModel(数据库模型)用作表示层(MVC)中的ViewModel。这三种模型都具有同一性。