【问题标题】:How to create a FileUpload view / viewmodel that isn't an entity in the database如何创建不是数据库中实体的 FileUpload 视图/视图模型
【发布时间】:2018-06-08 15:51:33
【问题描述】:

我正在开发一个拍卖应用程序,我正在创建一种方法,以便管理员可以提交一个 Excel 电子表格,该电子表格将创建一个新的拍卖并将其存储在数据库中。所以首先我创建了一个类(模型)Uploadfile,如下所示:

[NotMapped]
public class UploadFile
{
    [Required]
    public HttpPostedFileBase ExcelFile { get; set; }
}

我使用NotMapped 是因为我试图了解如何创建和使用未存储在我的数据库中的模型,这就是我的问题和误解所在。

我创建了一个控制器,这是我手动完成的,因为 UploadFile 不是具有这样键的实体:

public class FileUploadsController : Controller
{
    private AuctionEntities db = new AuctionEntities();

    // GET: FileUploads
    public ActionResult Index()
    {
        UploadFile UploadFile = new UploadFile();
        return View(UploadFile);
    }

    [HttpPost]
    public ActionResult Index(UploadFile UploadFile)
    {
        if (ModelState.IsValid)
        {
            if (UploadFile.ExcelFile.ContentLength > 0)
            {
                if (UploadFile.ExcelFile.FileName.EndsWith(".xlsx") || UploadFile.ExcelFile.FileName.EndsWith(".xls"))
                {
                    XLWorkbook wb;

                    // in case if the file is corrupt
                    try
                    {
                        wb = new XLWorkbook(UploadFile.ExcelFile.InputStream);
                    }
                    catch (Exception ex)
                    {
                        ModelState.AddModelError(String.Empty, $"Check your file. {ex.Message}");
                        return View();
                    }

                    IXLWorksheet ws = null;

                    try   // in case the sheet you are looking for is not found
                    {
                        ws = wb.Worksheet("sheet1");
                    }
                    catch
                    {
                        ModelState.AddModelError(String.Empty, "Sheet not found");
                        return View();
                    }

                    var firstRowUsed = ws.FirstRowUsed();
                    var auctionRow = firstRowUsed.RowUsed().RowBelow();

                    // create auction
                    string auctionName = auctionRow.Cell(1).Value.ToString();
                    DateTimeOffset startDate = DateTimeOffset.Parse(auctionRow.Cell(2).Value.ToString());
                    DateTimeOffset endDate = DateTimeOffset.Parse(auctionRow.Cell(3).Value.ToString());
                    string folderName = auctionRow.Cell(4).Value.ToString();

                    Models.Auction auction = new Models.Auction(auctionName, startDate, endDate, folderName);
                    db.Auctions.Add(auction);

                    // find the next table
                    var nextRow = auctionRow.RowBelow();

                    while (nextRow.IsEmpty())
                    {
                        nextRow = nextRow.RowBelow();
                    }

                    const int catNameCol = 1;
                    var catRow = nextRow.RowUsed().RowBelow();

                    // get categories from ws table and add to the auction
                    while (!catRow.Cell(catNameCol).IsEmpty())
                    {
                        string catName = catRow.Cell(1).Value.ToString();
                        int seqNo = Convert.ToInt32(catRow.Cell(2).Value.ToString());
                        string fileName = catRow.Cell(3).Value.ToString();

                        Cat cat = new Cat(auction.AuctionId, catName, seqNo, fileName);
                        auction.Cats.Add(cat);

                        catRow = catRow.RowBelow();
                    }

                    var findNextRow = catRow.RowBelow();

                    while (findNextRow.IsEmpty())
                    {
                        findNextRow = findNextRow.RowBelow();
                    }

                    const int itemNameCol = 1;

                    var itemRow = findNextRow.RowUsed().RowBelow();

                    while(!itemRow.Cell(itemNameCol).IsEmpty())
                    {
                        string itemName = itemRow.Cell(1).Value.ToString();
                        string itemDesc = itemRow.Cell(2).Value.ToString();
                        string catName = itemRow.Cell(3).Value.ToString();
                        string modelNo = itemRow.Cell(4).Value.ToString();
                        decimal retailValue = Convert.ToDecimal(itemRow.Cell(5).Value.ToString());
                        string fileName = itemRow.Cell(6).Value.ToString();
                        decimal initialBid = Convert.ToDecimal(itemRow.Cell(7).Value.ToString());
                        decimal increment = Convert.ToDecimal(itemRow.Cell(8).Value.ToString());
                        Cat itemCat = null;

                        foreach(var cat in auction.Cats)
                        {
                            if(catName == cat.CatName)
                            {
                                itemCat = cat;
                            }
                        }

                        Item item = new Item(itemName, itemDesc, modelNo, retailValue, fileName, startDate, endDate, initialBid, increment, null, null, null, itemCat);
                        itemCat.Items.Add(item);

                        itemRow = itemRow.RowBelow();
                    }
                }
                else
                {
                    ModelState.AddModelError(String.Empty, "Only .xlsx and .xls files are allowed");
                    return View();
                }
            }
            else
            {
                ModelState.AddModelError(String.Empty, "Not a valid file");
                return View();
            }
        }

        db.SaveChanges();

        return View();
    }

接下来我想我会尝试再次创建一个视图,以便我可以显示用户上传文件的位置并查看我的方法是否有效,这就是我在asp.net中缺乏知识的地方。

所以我尝试创建一个 ViewModel,因为我之前创建的模型是一个数据模型,所以我可以使用这个 viewmodel 在我的视图页面上显示上传。我的 ViewModel 很简单,是:

public class FileUploadViewModel
{
    public HttpPostedFileBase ExcelFile { get; set; }
}

现在,我想为这个视图模型创建一个视图页面,它仍然认为这个模型有一个实体,并给我一个错误,它没有密钥等。我需要一个可以访问模型的视图页面Excel 文件在其中,我似乎无法弄清楚如何做到这一点。我已经阅读了视图模型,并且知道它们在 MVC 中的重要性,但是我似乎无法掌握如何使用它们。有人可以帮我了解如何在这里使用吗?

基本上,我想将此视图页面与我的模型或视图模型一起使用:

【问题讨论】:

  • 您说问题出在您的视图模型上,但您发布的代码似乎与此无关(除了视图模型类定义)。您的 DbContext 是什么样的,您是如何创建视图模型并尝试显示它的? UploadFile 是否应该是您的实体之一?它没有钥匙。
  • UploadFile 不是实体。我根本不想将它或上传的文件存储在我的数据库中。这只是我认为将 excel 文件放入控制器的一种方式,以便我可以做我想做的事情。我想要完成的是有一个视图页面,上面写着“单击此处上传文件”,他们在那里上传电子表格,而我发布的控制器完成了其余的工作。我正在尝试使用 UploadedFile 模型或我创建的视图模型作为我传递给视图的模型来创建一个视图页面,以便我可以完成此操作。
  • 我通过右键单击并添加一个类将我的模型和尝试的视图模型都添加到了我的模型文件夹中。这是我知道该怎么做的唯一方法。它认为我希望这些类作为实体,因此当我尝试使用任何一个作为模型创建视图页面时出现错误
  • 好的,所以除非我遗漏了什么,否则没有什么只是“成为”一个实体,并在您的 DbContext 上显式注册为 DbSet。你能用确切的错误信息更新问题吗?
  • 您的上传类不需要[NotMapped]。那是您的视图模型。现在创建一个对该视图模型进行强类型化的视图并使用它。

标签: c# asp.net-mvc entity-framework viewmodel


【解决方案1】:

我有根据的猜测是您卡在“添加视图”窗口中。

您可能正在选择需要模型的模板(例如 Create),选择您的 FileUploadViewModel 类作为模型以及您的上下文。

这样做会导致 Visual Studio“向导”尝试在内部将模型映射到您的上下文,这会导致您看到的错误。

而是选择Empty (without model) 作为模板,这将使ModelData Context 字段变灰。然后将创建您的视图而不会出现错误。

然后,您可以通过在顶部添加以下内容来告诉视图期待您的模型:

@model FileUploadViewModel

确保您完全符合 FileUploadViewModel(例如,在前面包含命名空间)。

您的方法现在应该使用您在视图顶部指定的模型:

public ActionResult Index()
{
    FileUploadViewModel UploadFile = new FileUploadViewModel();
    return View(UploadFile);
}

[HttpPost]
public ActionResult Index(FileUploadViewModel UploadFile)
{

}

这里的任何地方都不需要[NotMapped] 属性。

【讨论】:

  • 胡安回答得很好。正是我需要的。然后当我调用“Index”“FileUploads”时它会知道使用这个页面吗?
  • 如果我要在我的“拍卖”“索引”页面上放置此功能的操作链接?
  • @C.Math:指向页面的操作链接将在没有任何参数的情况下触发签名。您上传文件的视图将包含一个表单标签,该标签将回发到标有[HttpPost] 的方法。
猜你喜欢
  • 2012-06-11
  • 2021-04-14
  • 1970-01-01
  • 2015-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-29
  • 1970-01-01
相关资源
最近更新 更多