У меня есть приложение MVC ASP.Net, использующее Entity Framework v6.0 с таблицей Сотрудника.
Мы используем подход Code First со стандартным методом Create (CRUD), который имеет EF-поиск для существующих сотрудников, а также EF-поиск для сотрудников CreatedBy / ModifiedBy. Попытка создать макеты для обоих (заглушки объектов EF) не удалась.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "EmployeeID,TeamID,EmployeeADID,FirstName,MiddleName,LastName,EmailAddress,IsAdministrator,IsDeleted")] Employee employee)
{
if (ModelState.IsValid)
{
//Only unique employee IDs
var existingEmployee = db.Employees.FirstOrDefault(o => o.EmployeeADID == employee.EmployeeADID);
if(existingEmployee != null)
{
ViewBag.Error = "Employee ID must be unique, this employee (" + existingEmployee.FullName + ") already exists in the system.";
ViewBag.TeamID = new SelectList(db.Teams, "TeamID", "Name", employee.TeamID);
return View(existingEmployee);
}
SetAuditFields(employee);
db.Employees.Add(employee);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.TeamID = new SelectList(db.Teams, "TeamID", "Name", employee.TeamID);
return View(employee);
}
Проблема в вызове SetAuditFields
, и мне нужно смоделировать db.Employees.AsNoTracking
AsNoTracking для операции редактирования.
private void SetAuditFields(Employee employee, bool onlyModified = false)
{
char sep = '\\';
string pID = User.Identity.Name.Split(sep)[1].ToUpper();
var users = db.Employees.AsNoTracking().Where(c => c.EmployeeADID == pID || c.EmployeeID == employee.EmployeeID).ToList();
var currentUser = users.FirstOrDefault(u => u.EmployeeADID == pID);
if (onlyModified)
{
//Notice the AsNoTracking, when you set the db.Entry(object).State = EntityState.Modified; this query wont return anything as its in Modified Mode.
//var originalEmployee = db.Employees.AsNoTracking().FirstOrDefault(o => o.EmployeeID == employee.EmployeeID);
var originalEmployee = users.FirstOrDefault(o => o.EmployeeID == employee.EmployeeID);
employee.CreatedByID = originalEmployee.CreatedByID;
employee.CreatedDate = originalEmployee.CreatedDate;
employee.ModifiedByID = currentUser.EmployeeID;
employee.ModifiedDate = DateTime.Now;
}
else
{
employee.CreatedByID = currentUser.EmployeeID;
employee.CreatedDate = DateTime.Now;
employee.ModifiedByID = currentUser.EmployeeID;
employee.ModifiedDate = DateTime.Now;
}
}
Так, как мне издеваться db.Employees.AsNoTracking
после первоначального издевательства db.Employees
?
КОММЕНТАРИИ ЭТИХ ДВУХ ЛИНИЙ в приведенном ниже коде не работают и дают сбой:
"Элемент 'IQueryable.Provider' не реализован для типа 'DbSet 1Proxy' which inherits from 'DbSet
1'
Я также попробовал mockContext.SetupSequence
, но мне нужно поменять местами с включенным и выключенным AsNoTracking. Наверняка, должно быть, я что-то упускаю?
[TestMethod()]
public void Create_Submit_Test()
{
// Arrange
var employeeDoesntExist = new Employee { EmployeeID = 0, FirstName = "DoesntExist" };
var employeeAdmin = new Employee { EmployeeID=140, FirstName = "Bern", MiddleName = "", LastName = "O", EmployeeADID = "123", EmailAddress = "Bernard.O@a.com", TeamID = 1, IsDeleted = false, IsAdministrator = true };
var employeeNew = new Employee { FirstName = "Jez", MiddleName = "", LastName = "T", EmployeeADID = "321", EmailAddress = "Jeremy.Thompson@a.com", TeamID = 1, IsDeleted = false, IsAdministrator = true };
var mockContext = new Mock<ICTEntities>();
var employeeEmptyMock = base.GetQueryableMockDbSet(employeeDoesntExist);
var employeeAdminMock = base.GetQueryableMockDbSet(employeeAdmin);
//THESE TWO LINES COMMENTED OUT
//mockContext.Setup(m => m.Employees).Returns(employeeEmptyMock);
//mockContext.Setup(m => m.Employees.AsNoTracking()).Returns(employeeAdminMock);
mockContext.SetupSequence(x => x.Employees.AsNoTracking())
.Returns(employeeEmptyMock)
.Returns(employeeAdminMock);
//I dont want to save it to the Database, otherwise next time we run this the object will already exist, so I mock the call
mockContext.Setup(d => d.SaveChanges()).Returns(1);
var controller = new EmployeesController(mockContext.Object);
controller.ControllerContext = base.MockAccess().Object;
// Act
RedirectToRouteResult result = controller.Create(employeeNew) as RedirectToRouteResult;
// Assert
Assert.IsNotNull(result);
Assert.AreEqual("Index", result.RouteValues["Action"]);
}
Вот метод GetQueryableMockDbSet:
protected DbSet<T> GetQueryableMockDbSet<T>(params T[] sourceList) where T : class
{
var queryable = sourceList.AsQueryable();
var dbSet = new Mock<DbSet<T>>();
dbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider);
dbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression);
dbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
dbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator());
return dbSet.Object;
}