ASP.NET MVC 与抽象层的实体框架

本文关键字:实体 框架 抽象 NET MVC ASP | 更新日期: 2023-09-27 17:56:09

我正在尝试在PluralSight上扩展一个项目。 在这个项目中,我在数据库EmployeesDepartments中有两个表,在 DepartmentsEmployees 之间有 1 对多。 为了防止控制器知道我的DbContext我使用以下接口:

public interface IDepartmentDataSource
{
    IQueryable<Employee> Employees { get;  }
    IQueryable<Department> Departments { get; }
}

数据库上下文:

public class DepartmentDb : DbContext, IDepartmentDataSource
{
    public DbSet<Employee> Employees { get; set; }
    public DbSet<Department> Departments { get; set; }
    public DepartmentDb() :base("DefaultConnection") { }
    IQueryable<Employee> IDepartmentDataSource.Employees
    {
        get { return Employees; }
    }
    IQueryable<Department> IDepartmentDataSource.Departments
    {
        get { return Departments; }
    }
    //this is the part that's wrong I believe
    public void AddDepartment(Department dept)
    {
        this.Departments.Add(dept);
        this.SaveChanges();
    }
}

控制器

public class DepartmentController : Controller
{
    //private readonly IDepartmentDataSource _db = new DepartmentDb();
    DepartmentDb _db = new DepartmentDb();
    public DepartmentController(DepartmentDb db)
    {
        _db = db;
    }
    public ActionResult Detail(int id)
    {
        var model = _db.Departments.Single(x => x.Id == id);
        return View(model);
    }
    [HttpGet]
    public ActionResult Create()
    {
        return View(new Department());
    }
    [HttpPost]
    public ActionResult Create(Department department)
    {
        _db.AddDepartment(department);
        _db.SaveChanges();
        return View(department);
    }
}

视图:

@model eManager.Domain.Department
@{
    ViewBag.Title = "Create";
}
<h2>Create</h2>
    @using (Html.BeginForm("Create","Department"))
    {
            <fieldset>
            <legend>City</legend>
            <div class="editor-label">
                @Html.LabelFor(model => model.Id)
            </div>
            <div class="editor-field">
                @Html.EditorFor(model => model.Id)
                @Html.ValidationMessageFor(model => model.Id)
            </div>
            <div class="editor-label">
                @Html.LabelFor(model => model.Name)
            </div>
            <div class="editor-field">
                @Html.EditorFor(model => model.Name)
                @Html.ValidationMessageFor(model => model.Name)
            </div>
            <p>
                <input type="submit" value="Create" />
            </p>
        </fieldset>
    }

这似乎是使用存储库模式(我无法实现端到端)的好地方。 但是当我尝试提交表单时,我收到一条错误消息,指出未传递参数。 为什么 MVC 不挑选已发布的表单值作为参数?

ASP.NET MVC 与抽象层的实体框架

你不会给自己买任何东西来做这样的抽象。用于DbContext的 API 会向控制器操作公开,即使实际的 DbContext 类不是。无论如何,更改为另一个 ORM、WCF 服务等将从根本上影响您的操作代码。

如果你想要一个真正的抽象,创建一个存储库或服务类,它将在其构造函数中获取DbContext的实例,然后通过自定义 API 公开DbSet的结果(即不要只返回DbSet或可查询)。

为了将这些不同的存储库或服务连接在一起,以便您最终不会得到上下文的多个实例,传统上,您需要创建类作为工作单元,由存储库或服务组成。但是,通过这样做,您基本上只是创建了一个俄罗斯套娃,其中您在工作单元内的存储库中有一个工作单元。我发现这里更好的方法是使用依赖项注入框架,为您的上下文使用每个请求范围生存期管理器。这样,相同的上下文实例就会馈送到 DI 容器实例化的每个存储库或服务中。

同样,我会引导您更多地使用服务而不是存储库。它主要是语义,但服务应该有更具体的方法(blogPostService.GetMostRecentPublishedPosts() vs. blogPostRepo.GetAll() )并返回完全烘焙的数据(无需进一步查询),而存储库通常返回一组未成形的数据,您需要进一步过滤、排序等。

尝试传入"FormCollection",看看会发生什么

    [HttpPost]
    public ActionResult Create(FormCollection form)
    {
        // new up a viewmodel here or something
        var model = new Department();
        // database stuff
    }