Only the first Mokcito.when is working here, resulting it to return a null, instead of the object.
Ive return two when as, there are two JPA functions being caled inside the service method.
#Test
public void testEditComplaintStatusDetail() {
long id = 1;
String status = "Investigation Complete";
EmergencyComplaint editedComplaint = new EmergencyComplaint(id, "No dogs to feed", "Investigation Complete");
when(emergencyComplaintRepository.findById(id)).thenReturn(Optional.of(emergencyComplaint));
when(emergencyComplaintRepository.save(editedComplaint)).thenReturn(editedComplaint);
assertEquals(emergencyComplaintService.editComplaintStatusDetails(status, id), editedComplaint);
}
Service
#Override
public EmergencyComplaint findComplaintDetailsById(long id) {
return emergencyComplaintDAO.findById(id);
}
#Override
public EmergencyComplaint editComplaintStatusDetails(String status, long id) {
EmergencyComplaint complaint = findComplaintDetailsById(id);
complaint.setStatus(status);
return emergencyComplaintDAO.save(complaint);
}
DAO
#Override
public EmergencyComplaint findById(long id) {
return emergencyComplaintRepository.findById(id).orElse(null);
}
#Override
public EmergencyComplaint save(EmergencyComplaint emergencyComplaint) {
return emergencyComplaintRepository.save(emergencyComplaint);
}
Update after edit:
Your mock for save() won't work if your EmergencyComplaint object does not equals to your editedComplaint object. So you have to change (or at least show) your equals function or widen your expected mocking parameters like this:
when(emergencyComplaintRepository.save(Mockito.any())).thenReturn(editedComplaint);
Related
I would like to return two different response for a spring boot rest API.
I should not be using <?> wild card as i get the sonar issue "Generic wildcard types should not be used in return types"
My code:
#GetMapping(path = {"/v1/{type}"}, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> method(#PathVariable(value = "type") boolean type) {
boolean b = type;// some logic
if (b) {
Success result=new Success();
result.setSuccess("Yes");
return new ResponseEntity<>(result,HttpStatus.OK);
}
else {
Error result=new Error();
result.setError("No");
return new ResponseEntity<>(result,HttpStatus.CONFLICT); //appropriate error code
}
}
Any idea how to handle this situation.
Update:
public interface MyResponse{
public Success getSuccessObj();
public Error getErrorObj();
}
#Service
public class Success implements MyResponse {
public Error getErrorObj(){
return null;
}
public Success getSuccessObj(){
Success s=new Success();
return s;
}
#Service
public class Error implements MyResponse {
public Error getErrorObj(){
Error e=new Error();
return e;
}
public Success getSuccessObj(){
return null;
}
Not claiming to be "the best way", but one approach can be:
Introduce:
package com.my.package;
public interface MyResponseI { //if Error, Success (and others) have more "in common", you can also introduce an (abstract) class (with fields, methods, etc.)!
}
"Implement"/Extend:
public class Success implements com.my.package.MyResponseI { //everything else can stay}
as
public class Error implements com.my.package.MyResponseI { //everything else can stay}
Use as Response Type:
#...
public ResponseEntity<com.my.package.MyResponseI> ...
(on client side distinguish).
..and in "your domain" (error, success, ...), you are free to use any "tweaks" of a object oriented design.
Useful links/entries:
https://stackoverflow.blog/2020/03/02/best-practices-for-rest-api-design/
https://swagger.io/resources/articles/best-practices-in-api-design/
https://www.google.com/search?q=rest+api+design
, but also
https://www.google.com/search?q=object+oriented+design
and https://www.google.com/search?q=domain+driven+design
This should work
I tried the snippet below by myself and it worked for me:
#GetMapping("/testresponse/{id}")
public ResponseEntity<?> testMyResponse(#PathVariable("id") int id)
{
if(id==1)
return ResponseEntity.ok(new Success());
else return new ResponseEntity<>(new Error(), HttpStatus.CONFLICT);
}
public class Success {
private String msg = "Success";
public String getMsg() {
return msg;
}
}
public class Error {
private String msg = "Error";
public String getMsg() {
return msg;
}
}
EDIT: The solution as below doesn't work
You should also define an interface for both Success and Error classes. Let say the interface MyResponse
And then change your method declaration, it would look like this
public ResponseEntity<MyResponse> method(#PathVariable(value = "type") boolean type)
If so, the return statement, could be:
return new ResponseEntity<>(result, HttpStatus.OK);
Or
//for status 200 OK
return ResponseEntity.ok(result);
I am playing with Spring's WebClient. The primary implementation of the REST endpoints (in DemoPOJORouter and DemoPOJOHandler) seem to work. Also, the http.Get endpoint in DemoClientRouter and DemoClientHandler seems to work.
But, the http.Post for the DemoClient implementation "does nothing". It returns success (200), but nothing gets added to the dummy repo. I have a feeling that I need to do something in DemoClient to cause the http.Post endpoint in DemoPOJOHandler to actually execute (i.e., I believe neither the statements in DemoPOJOService.add() nor DemoPOJORepo.add() are being executed).
Based on prior pratfalls in WebFlux/reactive/functional efforts, I have a feeling that I'm not successfully subscribing, and so the statements never are invoked. But, I'm having difficulty identifying the "why".
Test code follows...
DemoClient router...
#Configuration
public class DemoClientRouter {
#Bean
public RouterFunction<ServerResponse> clientRoutes(DemoClientHandler requestHandler) {
return nest(path("/v2"),
nest(accept(APPLICATION_JSON),
RouterFunctions.route(RequestPredicates.GET("/DemoClient/{id}"), requestHandler::getById)
.andRoute(RequestPredicates.POST("/DemoClient"), requestHandler::add)));
}
}
DemoClient handler...
#Component
public class DemoClientHandler {
public static final String PATH_VAR_ID = "id";
#Autowired
DemoClient demoClient;
public Mono<ServerResponse> getById(ServerRequest request) {
Mono<DemoPOJO> monoDemoPOJO;
int id;
// short-circuit if bad request or invalid value for id
id = getIdFromServerRequest(request);
if (id < 1) {
return ServerResponse.badRequest().build();
}
// non-blocking mechanism for either returning the Mono<DemoPOJO>
// or an empty response if Mono<Void> was returned by repo.getById()
return demoClient.getById(id).flatMap(demoPOJO -> ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(Mono.just(demoPOJO), DemoPOJO.class))
.switchIfEmpty(ServerResponse.notFound().build());
}
public Mono<ServerResponse> add(ServerRequest request) {
return request.bodyToMono(DemoPOJO.class).doOnSuccess( demoPOJO -> demoClient.add(demoPOJO))
.then(ServerResponse.ok().build())
.onErrorResume(e -> simpleErrorReporter(e))
.switchIfEmpty(ServerResponse.badRequest().build());
}
private int getIdFromServerRequest(ServerRequest request) {
Map<String, String> pathVariables = request.pathVariables();
int id = -1;
// short-circuit if bad request
// should never happen, but if this method is ever called directly (vice via DemoPOJORouter)
if ((pathVariables == null)
|| (!pathVariables.containsKey(PATH_VAR_ID))) {
return id;
}
try {
id = Integer.parseInt(pathVariables.get(PATH_VAR_ID));
} catch (NumberFormatException e) {
// swallow the error, return value <0 to signal error
id = -1;
}
return id;
}
private Mono<ServerResponse> simpleErrorReporter(Throwable e) {
return ServerResponse.badRequest()
.contentType(MediaType.TEXT_PLAIN)
.syncBody(e.getMessage());
}
}
DemoClient impl...
#Component
public class DemoClient {
private final WebClient client;
public DemoClient() {
client = WebClient.create();
}
public Mono<DemoPOJO> getById(int id) {
return client.get().uri("http://localhost:8080/v2/DemoPOJO/" + id)
.accept(MediaType.APPLICATION_JSON)
.exchange()
.flatMap(response -> response.bodyToMono(DemoPOJO.class));
}
public Mono<Boolean> add(DemoPOJO demoPOJO) {
return client.post().uri("http://localhost:8080/v2/DemoPOJO")
.syncBody(demoPOJO)
.exchange()
.flatMap(response -> response.bodyToMono(Boolean.class));
}
}
And, the DemoPOJO stuff, starting with DemoPOJORouter...
#Configuration
public class DemoPOJORouter {
#Bean
public RouterFunction<ServerResponse> demoPOJORoute(DemoPOJOHandler requestHandler) {
return nest(path("/v2"),
nest(accept(APPLICATION_JSON),
RouterFunctions.route(RequestPredicates.GET("/DemoPOJO/{id}"), requestHandler::getById)
.andRoute(RequestPredicates.POST("/DemoPOJO"), requestHandler::add)));
}
}
DemoPOJOHandler...
#Component
public class DemoPOJOHandler {
public static final String PATH_VAR_ID = "id";
#Autowired
private DemoPOJOService service;
public Mono<ServerResponse> getById(ServerRequest request) {
Mono<DemoPOJO> monoDemoPOJO;
int id;
// short-circuit if bad request or invalid value for id
id = getIdFromServerRequest(request);
if (id < 1) {
return ServerResponse.badRequest().build();
}
// non-blocking mechanism for either returning the Mono<DemoPOJO>
// or an empty response if Mono<Void> was returned by repo.getById()
return service.getById(id).flatMap(demoPOJO -> ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(Mono.just(demoPOJO), DemoPOJO.class))
.switchIfEmpty(ServerResponse.notFound().build());
}
public Mono<ServerResponse> add(ServerRequest request) {
return request.bodyToMono(DemoPOJO.class).doOnSuccess( demoPOJO -> service.add(demoPOJO))
.then(ServerResponse.ok().build())
.onErrorResume(e -> simpleErrorReporter(e))
.switchIfEmpty(ServerResponse.badRequest().build());
}
private int getIdFromServerRequest(ServerRequest request) {
Map<String, String> pathVariables = request.pathVariables();
int id = -1;
// short-circuit if bad request
// should never happen, but if this method is ever called directly (vice via DemoPOJORouter)
if ((pathVariables == null)
|| (!pathVariables.containsKey(PATH_VAR_ID))) {
return id;
}
try {
id = Integer.parseInt(pathVariables.get(PATH_VAR_ID));
} catch (NumberFormatException e) {
// swallow the exception, return illegal value to signal error
id = -1;
}
return id;
}
private Mono<ServerResponse> simpleErrorReporter(Throwable e) {
return ServerResponse.badRequest()
.contentType(MediaType.TEXT_PLAIN)
.syncBody(e.getMessage());
}
}
DemoPOJOService...
#Component
public class DemoPOJOService {
#Autowired
private DemoPOJORepo demoPOJORepo;
public Mono<DemoPOJO> getById(int id) {
DemoPOJO demoPOJO = demoPOJORepo.getById(id);
return (demoPOJO == null) ? Mono.empty()
: Mono.just(demoPOJO);
}
public Mono<Boolean> add(DemoPOJO demoPOJO) {
return Mono.just(demoPOJORepo.add(demoPOJO));
}
}
DemoPOJORepo...
#Component
public class DemoPOJORepo {
private static final int NUM_OBJS = 5;
private static DemoPOJORepo demoRepo = null;
private Map<Integer, DemoPOJO> demoPOJOMap;
private DemoPOJORepo() {
initMap();
}
public static DemoPOJORepo getInstance() {
if (demoRepo == null) {
demoRepo = new DemoPOJORepo();
}
return demoRepo;
}
public DemoPOJO getById(int id) {
return demoPOJOMap.get(id);
}
public boolean add(DemoPOJO demoPOJO) throws InvalidParameterException {
// short-circuit on null pointer or duplicate id
if (demoPOJO == null) {
throw new InvalidParameterException("Add failed, null object detected...");
} else if (demoPOJOMap.containsKey(demoPOJO.getId())) {
throw new InvalidParameterException("Add failed, duplicate id detected...");
}
demoPOJOMap.put(demoPOJO.getId(), demoPOJO);
// if the return statement is reached, then the new demoPOJO was added
return true;
}
}
Finally, DemoPOJO...
public class DemoPOJO {
public static final String DEF_NAME = "DEFAULT NAME";
public static final int DEF_VALUE = 99;
private int id;
private String name;
private int value;
public DemoPOJO(int id) {
this(id, DEF_NAME, DEF_VALUE);
}
public DemoPOJO(#JsonProperty("id") int id, #JsonProperty("name") String name, #JsonProperty("value") int value) {
this.id = id;
this.name = name;
this.value = value;
}
/*
* setters and getters go here
*/
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(id);
builder.append(" :: ");
builder.append(name);
builder.append(" :: ");
builder.append(value);
return builder.toString();
}
}
Here is probably your problem.
DemoPOJOHandler.class
request.bodyToMono(DemoPOJO.class).doOnSuccess(demoPOJO -> service.add(demoPOJO))
DemoPOJOService.class
public Mono<Boolean> add(DemoPOJO demoPOJO) {
return Mono.just(demoPOJORepo.add(demoPOJO));
}
doOnSuccess returns Void, but you are calling a method that wraps the "action" in a returning Mono. So the demoPOJORepo#add function will never be triggered because you have broken the event chain here. The easiest fix is to just remove the wrapping Mono and return void.
public void add(DemoPOJO demoPOJO) {
demoPOJORepo.add(demoPOJO);
}
This took me way to long to find so here are some pointers when asking a question.
The names of your classes are too like each other, it was hard to follow the codeflow.
DemoPOJOService service your names are so alike so when i saw service was it the DemoPOJOService or the DemoClientService? clear names please.
There is nothing called http.POST when you wrote that i had no idea what you where talking about.
you had problems with the POST part but you posted everything, even the working GET parts, please only post code you suspect is relevant and are part of the problem.
Explain the question more clearly, what you have done, how you do it, what your application structure is and so fourth
Your endpoint urls say nothing "/DemoClient"?
How this question could have been asked to be more clear:
I have two endpoints in two routers in the same spring reactive
application.
When I do a POST request to the "/add" endpoint, this endpoint in turn
makes an a POST call using a WebClient to the same application just on
another endpoint called "/addToMap".
When this first call returns, it returns me a 200 OK status but when i
check the map (that the second endpoint is supposed to add the posted
data to) nothing gets added.
So please, next time asking a question, be clear, very clear, a lot clearer than you think. make sure your code is clear too with good variable and class names and clear url names. If you have messy names on your own computer its fine but when posting here be polite and clean up the code .It takes 5 minutes to add good names to classes and parameters so that we understand your code quicker.
take the time to read the "how to ask a good question" please.
How to ask a good question
I'm fiddling around with Mockito and Spring MVC. I'm trying to write unit tests for the code I've just written.
This is my CategoryService class:
#Service
public class CategoryService {
#Autowired
#Qualifier("categoryDaoImpl")
private CategoryDao categoryDao;
public void addCategory(Category category) {
category.setId(getLastCategoryId() + 1);
categoryDao.addCategory(category);
}
public Category getCategoryById(int id) {
return categoryDao.getCategoryById(id);
}
public List<Category> getCategories() {
return categoryDao.getAllCategories();
}
public int getCategoriesCount() {
return categoryDao.getCategoriesCount();
}
public int getLastCategoryId() {
if (categoryDao.getAllCategories().size() == 0) {
return 0;
}
return Collections.max(categoryDao.getAllCategories()).getId();
}
public CategoryDao getCategoryDao() {
return categoryDao;
}
public void setCategoryDao(CategoryDao categoryDao) {
this.categoryDao = categoryDao;
}
I've already tested CategoryDao with nearly 100% coverage.
And now I want to test CategoryService, but I have no idea how to test it, I mean methods like: addCategory, getCategoryById, getAllCategories, getCategoiesCount etc.
They're just talking to the DAO pattern, but what if another person changes its logic? I'd be glad if you told me or showed how to write a tests for such short methods.
As far as CategoryService is concerned, I only wrote tests for getLastCategoryId():
#Test
public void shouldGetLastCategoryIdWhenListIsEmpty() {
//given
List<Category> list = new ArrayList<Category>();
Mockito.when(categoryDao.getAllCategories()).thenReturn(list);
//when
int lastCategoryId = categoryService.getLastCategoryId();
//then
assertThat(lastCategoryId, is(0));
}
#Test
public void shouldGetLastCategoryIdWhenListIsNotEmpty() {
//given
List<Category> list = new ArrayList<Category>();
list.add(new Category(1, "a", "a"));
list.add(new Category(3, "a", "a"));
list.add(new Category(6, "a", "a"));
Mockito.when(categoryDao.getAllCategories()).thenReturn(list);
//when
int lastCategoryId = categoryService.getLastCategoryId();
//then
assertThat(lastCategoryId, is(6));
}
Thank you very much for help :)
Best regards,
Tom
You need to verify that the service methods behave as per their contracts even if they are modified in the future.
For e.g. The addCategory(Category c) method adds the category. This can be verified by verifying the categoryDao.addCategory() method is called with the category object that has the required properties set. In this case the id should be set to the lastCategoryId. Verifying could simply be done by create a spy of CategoryDao class (would be simpler then using third party libraries like mockito.
The test cases for getCategoryById(), getCategories() and getCategoriesCount() method could verify that the values returned are the ones returned by the dao.
I understand that this would mean just one test case per method, but these test cases just confirm that if there is more logic added in the service method implementation, the contract remains intact.
Here's one test case for addCategory()
public class CategoryServiceTest {
private CategoryService service;
private CategoryDaoSpy daoSpy;
#Before
public void setUp() {
service = new CategoryService();
daoSpy = new CategoryDaoSpy();
service.setCategoryDao(daoSpy);
}
#Test
public void shouldSaveCategoryWhenCategoryPassed() {
Category category = new Category();
service.addCategory(category);
assertEquals(daoSpy.getAddCategoryCallCount(), 1);
assertEquals(daoSpy.getCategories().size(), 1);
assertEquals(daoSpy.getCategories().get(0).getId(), 1);
}
}
public class CategoryDaoSpy extends CategoryDao {
private int addCategoryCallCount = 0;
private List<Category> categories = new ArrayList<>();
#Override
public void addCategory(Category category) {
this.addCategoryCallCount++;
categories.add(category);
}
public int getAddCategoryCallCount() {
return addCategoryCallCount;
}
public List<Category> getCategories() {
return categories;
}
#Override
public List<Category> getAllCategories() {
return Collections.emptyList();
}
}
I am trying to mock a getBy() method after adding an element by a mocked service add.
This is what I have:
FeedItem feedItem = feedServiceTested.createFeedItem("Text Test", "Category Test", "Author Test");
Mockito.verify(feedRepository).add(feedItem);
Mockito.verify(feedRepository).findAllByCategory("Category Test");
However I get the following error:
Wanted but not invoked:
feedRepository.findAllByCategory(
"Category Test"
);
-> at ie.cit.adf.services.FeedServiceImplTest.testSearchFeedItemsByCategory(FeedServiceImplTest.java:55)
However, there were other interactions with this mock:
-> at ie.cit.adf.services.FeedServiceImpl.createFeedItem(FeedServiceImpl.java:44)
at ie.cit.adf.services.FeedServiceImplTest.testSearchFeedItemsByCategory(FeedServiceImplTest.java:55)
Any idea how to mock this findAllByCategory()?
Here are the 2 classes:
Repository:
#Secured("ROLE_USER")
public class JdbcFeedRepository implements FeedRepository {
private JdbcTemplate jdbcTemplate;
private FeedItemsMapper feedItemsMapper = new FeedItemsMapper();
public JdbcFeedRepository(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
}
#Override
public FeedItem findById(String feedItemId) {
return jdbcTemplate.queryForObject(
"SELECT ID, TEXT, CATEGORY, AUTHOR FROM FEEDITEMS WHERE ID=?",
feedItemsMapper,
feedItemId
);
}
#Override
public List<FeedItem> findAll() {
return jdbcTemplate.query(
"SELECT ID, TEXT, CATEGORY, AUTHOR FROM FEEDITEMS",
feedItemsMapper
);
}
#Override
public List<FeedItem> findAllByCategory(String category) {
return jdbcTemplate.query(
"SELECT ID, TEXT, CATEGORY, AUTHOR FROM FEEDITEMS WHERE CATEGORY=?",
feedItemsMapper,
category
);
}
#Override
public List<FeedItem> findAllByAuthor(String author) {
return jdbcTemplate.query(
"SELECT ID, TEXT, CATEGORY, AUTHOR FROM FEEDITEMS WHERE AUTHOR=?",
feedItemsMapper,
author
);
}
#Override
public void add(FeedItem feedItem) {
jdbcTemplate.update(
"INSERT INTO FEEDITEMS VALUES(?,?,?,?)",
feedItem.getId(),
feedItem.getText(),
feedItem.getCategory(),
feedItem.getAuthor()
);
}
#Override
public void delete(String feedItemId) {
jdbcTemplate.update("DELETE FROM FEEDITEMS WHERE ID=?", feedItemId);
}
/**
* Returns the name of the currently logged in Author.
*
* #return String
*/
private String getCurrentUser() {
return SecurityContextHolder.getContext().getAuthentication().getName();
}
}
class FeedItemsMapper implements RowMapper<FeedItem> {
#Override
public FeedItem mapRow(ResultSet rs, int rowNum) throws SQLException {
FeedItem feedItem = new FeedItem();
feedItem.setId(rs.getString("ID"));
feedItem.setText(rs.getString("TEXT"));
feedItem.setCategory(rs.getString("CATEGORY"));
feedItem.setAuthor(rs.getString("AUTHOR"));
return feedItem;
}
}
Service:
#Transactional
public class FeedServiceImpl implements FeedService {
private FeedRepository repo;
public FeedServiceImpl(FeedRepository repo) {
this.repo = repo;
}
#Override
public FeedItem get(String feedItemId) {
return repo.findById(feedItemId);
}
#Override
public List<FeedItem> getAllFeedItems() {
return repo.findAll();
}
#Override
public List<FeedItem> getAllFeedItemsByCategory(String category) {
return repo.findAllByCategory(category);
}
#Override
public List<FeedItem> getAuthorFeedItems(String author) {
return repo.findAllByAuthor(author);
}
#Override
public FeedItem createFeedItem(String text, String category, String author) {
FeedItem feedItem = new FeedItem();
feedItem.setText(text);
feedItem.setCategory(category);
feedItem.setAuthor(author);
repo.add(feedItem);
return feedItem;
}
#Override
public void delete(String feedItemId) {
repo.delete(feedItemId);
}
}
It seems your code never calls:
feedRepository.findAllByCategory("Category Test");
But you added a verifier for it. Mockito verify ensures the method is called one time in your test. When this did not happen its complains with an exception.
Your test calls:
feedServiceTested.createFeedItem(...)
Which only calls the following methods on repo:
add(feedItem)
Which is your first verify. So at the moment it seems your code did not use findAllByCategory and so does the verify throws this exception.
Or is there a call in FeedItem to the repo? Then please provide the code for this class too.
This code works fine, However, if I run execute a storedprocedure in my unit of work class (or any update, delete, add operation), I'm still getting original the data. Actually, I have already a solution(posted below in controller) but Im sure this is not the most elegant way, I hope someone can help me refactor the code. please help. Thanks
My unit of work
public class UnitOfWork : IUnitOfWork, IDisposable
{
private readonly ObjectContext _context;
private BookRepository _books;
public UnitOfWork(ObjectContext context)
{
if (context == null)
{
throw new ArgumentNullException("Context was not supplied");
}
_context = context;
}
public IRepository<Book> Books
{
get
{
if (_books== null)
{
_books= new BookRepository (_context);
}
return _books;
}
}
public void UpdateAuthor(int id)
{
_context.ExecuteStoreCommand("sp_UpdateAuthor #param1",
new SqlParameter("param1", id));
}
public void Commit()
{
_context.SaveChanges();
}
Book Repository
public class BookRepository : Repository<Book>
{
public BookRepository (ObjectContext context)
: base(context)
{
}
public override Machine GetById(object id)
{
return _objectSet.SingleOrDefault(s => s.Id== (int)id);
}
}
Generic Repository
public abstract class Repository<T> : IRepository<T>
where T : class, IAuditEntity
{
protected IObjectSet<T> _objectSet;
public Repository(ObjectContext context)
{
_objectSet = context.CreateObjectSet<T>();
}
public abstract T GetById(object id);
public IEnumerable<T> GetAll()
{
return _objectSet;
}
public IEnumerable<T> Query(Expression<Func<T, bool>> filter)
{
return _objectSet.Where(filter);
}
public void Add(T entity)
{
_objectSet.AddObject(entity);
}
public void Remove(T entity)
{
_objectSet.DeleteObject(entity);
}
}
Controller Code
public class HomeController : Controller
{
private IUnitOfWork _unitOfWork;
#region Core Action Methods
public HomeController()
{
this._unitOfWork = new UnitOfWork(((IObjectContextAdapter)new BookContext()).ObjectContext);
}
private IEnumerable<BookViewModel> GetBookdsViewModels(int id)
{
//THE CODE WHERE ITS NOT RETURNING THE UPDATED VLAUES
//var query = _unitOfWork.Books.GetAll().Where(d => d.Id== id);
//I WANT TO CHANGE THIS CODE
ObjectContext objectContext = ((IObjectContextAdapter)new BookContext()).ObjectContext;
ObjectSet<Book> set = objectContext.CreateObjectSet<Book>();
set.MergeOption = MergeOption.OverwriteChanges;
var query = from a in set
where a.Id== id && !a.IsDeleted
select a;
return query
.Select(
c => new BookViewModel
{
Id = c.Id ,
Name = c.Name
});
}
I believe the problem is because you're executing things directly against your database, and then trying to refer back to the local copy that's stored in your repository and they're different.
public void UpdateAuthor(int id)
{
_context.ExecuteStoreCommand("sp_UpdateAuthor #param1",
new SqlParameter("param1", id));
}
When you run this query, you're making a change in your db instead of your local - why dont you do something like this:
public void UpdateAuthor(int id)
{
var book = Books.GetById(id);
/* make changes to your book object */
_unit.Save();
}
If you're wanting to make changes using store procs, you're going to have to dispose of your context, and recreate the repo's so that you're working with data from the DB instead of the local copy.
Expanding on Mark Oreta's answer, you need to ensure your Model is updated after manually executing a stored proc on your database. If you must manually call that stored proc then try this afterward:
_context.Entry<Book>(instanceOfAuthor).Reload();
Which might be:
_context.Entry<Book>(_context.Books.GetById(id)).Reload();