How to custom response in asp.net web api2 - c#

the problem in this function when add this two lines.
UserImage = GetImagePath(db.Users.FirstOrDefault(x => x.Id == p.User_ID).Image),
InsertDate = p.InsertDate.ToString("dd/MM/yyyy")
I need to custom Image Path and custom date format,show this problem.
LINQ to Entities does not recognize the method System.String ToString(System.String) method, and this method cannot be translated into a store expression
private static string GetImagePath(string ImageName)
{
return System.Configuration.ConfigurationManager.AppSettings["websiteurl"].ToString() + "/uploads/" + ImageName;
}
[HttpGet]
[Route("Comments")]
public IHttpActionResult Comments(string Post_ID)
{
var list = db
.ShalehComments
.Where(p => p.Shaleh_ID == Post_ID && p.ParentID == 0)
.Select(p => new {
ID = p.ID,
Comment = p.Comment,
User = db.Users.FirstOrDefault(x=> x.Id == p.User_ID).FullName,
UserImage = GetImagePath(db.Users.FirstOrDefault(x => x.Id == p.User_ID).Image),//here problem
InsertDate = p.InsertDate.ToString("dd/MM/yyyy")//and here
}).ToList();
return Ok(
new
{
result = true,
data = list
}
);
}

This error occurred because Entity Framework does not know how to execute .ToString() or GetImagePath method in sql. So you should load the data by using ToList.So you try something like:
[HttpGet]
[Route("Comments")]
public IHttpActionResult Comments(string Post_ID)
{
var list = db
.ShalehComments
.Where(p => p.Shaleh_ID == Post_ID && p.ParentID == 0)
.ToList()//add ToList
.Select(p => new {
ID = p.ID,
Comment = p.Comment,
User = db.Users.FirstOrDefault(x=> x.Id == p.User_ID).FullName,
UserImage = GetImagePath(db.Users.FirstOrDefault(x => x.Id == p.User_ID).Image),
InsertDate = p.InsertDate.ToString("dd/MM/yyyy")//and here
}).ToList();
return Ok(
new
{
result = true,
data = list
}
);
}

Related

Reusing queries with Entity Framework Core

I'm trying to make some queries using EF-Core and I have the following code
public List<Visitation> GetAllVisitations()
{
return this.hospital.Visitations
.Where(v => v.DoctorId == this.Doctor.Id)
.Select(v => new Visitation
{
Doctor = v.Doctor,
Patient = v.Patient,
Date = v.Date,
Comments = v.Comments
})
.ToList();
}
public List<Visitation> GetVisitationByPatient(int id)
{
var patient = this.GetPatientById(id);
return this.hospital.Visitations
.Where(v => v.PatientId == patient.Id)
.Select(v => new Visitation
{
Doctor = v.Doctor,
Patient = v.Patient,
Date = v.Date,
Comments = v.Comments
})
.ToList();
}
It is pretty obvious that the Select statement is the same in both methods. However I know that EF Core uses Expression<Func>, rather than Func therefore I do not know how to make an Expression, which can be used in both Select statements.
The query won't execute until you call .ToList(). So you may take the partial query up to the .Where() and pass it to a function that adds the Select() portion.
Something like this:
public List<Visitation> GetAllVisitations()
{
var query = this.hospital.Visitations
.Where(v => v.DoctorId == this.Doctor.Id);
return this.addTransformation(query)
.ToList();
}
public List<Visitation> GetVisitationByPatient(int id)
{
var patient = this.GetPatientById(id);
var query = this.hospital.Visitations
.Where(v => v.PatientId == patient.Id)
return this.addTransformation(query)
.ToList();
}
public IQueriable<Visitation> AddTransformation(IQueriable<Visitation> query)
{
return query.Select(v => new Visitation
{
Doctor = v.Doctor,
Patient = v.Patient,
Date = v.Date,
Comments = v.Comments
});
}

Push multiple objects with dynamic data into a DTO and return it

So I'm trying to use a DTO to reshape and return data, it's not working because I'm trying to push in an array of objects (as an IQueryable - which I don't think works) into the DTO, I'm also trying to push in dynamic data into one of the properties, as seen below in the 'hasCurrentUserLiked' property. I need to figure out How to change the objects from IQueryable, into actual objects so they can all be pushed into the DTO and the dynamic data can be worked out.
This is the code
public async Task<PagedList<UserPhoto>> GetSpecificFeed(UserParams userParams)
{
var user = _context.Users.FirstOrDefault(x => x.Username == userParams.u);
var userId = user.Id;
var photos = _context.UserPhotos;
var followerIds = _context.Follows.Where(x => x.FollowerId == userId).Select(x => x.FollowingId).ToList();
var feeds = _context.UserPhotos.Where(x => followerIds.Contains(x.UserId)).OrderByDescending(x => x.DateAdded);
// this doesn't work because 'feeds' is an IQueryable, not an object
var like = await hasCurrentUserLiked(user.Id, feeds.id);
// this has the same problem as above
var feedsToReturn = new FeedsForReturnDto
{
Id = feeds.Id,
PhotoUrl = feeds.photoUrl,
Username = feeds.Username,
Description = feeds.Description,
DateAdded = feeds.DateAdded,
IsImage = feeds.IsImage,
hasCurrentUserLiked = like,
Likes = feeds.Likes
}
return await PagedList<UserPhoto>.CreateAsync(feedsToReturn, userParams.PageNumber, userParams.PageSize);
}
I thought that I might be able to get each image.id in a similar way the 'followerIds' are worked out but I couldn't figure out how to get this to work
[EDIT]
As per Enas Osamas answer, I've changed the code to this and I've debugged it, feedsToReturn has the correct info, so it is doing what its supposed to do. The problem I'm having now is that I'm unable to return it as it can't convert the IEnumerable to an IQueryable. I tried adding an explicit cast but that didn't work, I also tried removing the PagedList, and replacing the type to but this didn't work. My is an IQueryable which might be the problem, I tried changing that to an IEnumerable but this would mess up the code in other places.
This is my new code (still returning 'feeds' instead of 'feedsToReturn', will change when it works)
public async Task<PagedList<UserPhoto>> GetSpecificFeed(UserParams userParams)
{
var user = _context.Users.FirstOrDefault(x => x.Username == userParams.u);
var userId = user.Id;
var photos = _context.UserPhotos;
var followerIds = _context.Follows.Where(x => x.FollowerId == userId).Select(x => x.FollowingId).ToList();
var feeds = _context.UserPhotos.Where(x => followerIds.Contains(x.UserId)).OrderByDescending(x => x.DateAdded);
var feedToReturn = feeds.AsEnumerable().Select(feed => new FeedsForReturnDto
{
Id = feed.Id,
PhotoUrl = feed.photoUrl,
Username = feed.Username,
Description = feed.Description,
DateAdded = feed.DateAdded,
IsImage = feed.IsImage,
hasCurrentUserLiked = hasCurrentUserLiked(user.Id, feed.Id),
Likes = feed.Likes
});
return await PagedList<UserPhoto>.CreateAsync(feeds, userParams.PageNumber, userParams.PageSize);
}
I also tried changing some of the types around and this is what I came up with. The problem here is this:
'System.Collections.Generic.IEnumerable<cartalk.api.Dtos.feeds.FeedsForReturnDto>' to 'System.Linq.IQueryable<System.Collections.IEnumerable>'
and this problem is with the 'feedsToReturn' in the last line
public async Task<PagedList<IEnumerable>> GetSpecificFeed(UserParams userParams)
{
var user = _context.Users.FirstOrDefault(x => x.Username == userParams.u);
var userId = user.Id;
var photos = _context.UserPhotos;
var followerIds = _context.Follows.Where(x => x.FollowerId == userId).Select(x => x.FollowingId).ToList();
var feeds = _context.UserPhotos.Where(x => followerIds.Contains(x.UserId)).OrderByDescending(x => x.DateAdded);
var feedToReturn = feeds.AsEnumerable().Select(feed => new FeedsForReturnDto
{
Id = feed.Id,
PhotoUrl = feed.photoUrl,
Username = feed.Username,
Description = feed.Description,
DateAdded = feed.DateAdded,
IsImage = feed.IsImage,
hasCurrentUserLiked = hasCurrentUserLiked(user.Id, feed.Id),
Likes = feed.Likes
});
return await PagedList<IEnumerable>.CreateAsync(feedToReturn, userParams.PageNumber, userParams.PageSize);
}
PagedList code
public static async Task<PagedList<T>> CreateAsync(IQueryable<T> source,
int pageNumber, int pageSize)
{
var count = await source.CountAsync();
var items = await source.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToListAsync();
return new PagedList<T>(items, count, pageNumber, pageSize);
}
[EDIT]
This is the hasCurrentUserLiked function, it works here
public bool checkCurrentUserLiked(int currentUserId, int imageId)
{
var doesCurrentUserLike = _context.PhotoLikes.Where(x => x.LikerId == currentUserId && x.ImageId == imageId);
var value = true;
if (doesCurrentUserLike == null)
{
value = false;
}
else
{
value = true;
}
return value;
}
You can try something like
feeds.AsEnumerable().Select(feed => new FeedsForReturnDto
{
Id = feed.Id,
PhotoUrl = feed.photoUrl,
Username = feed.Username,
Description = feed.Description,
DateAdded = feed.DateAdded,
IsImage = feed.IsImage,
hasCurrentUserLiked = hasCurrentUserLiked(user.Id, feed.id),
Likes = feed.Likes
});
This would return an IEnumerable containing all the feeds mapped to your DTO after being enumerated to avoid performing operations against the database
[EDIT]
you can maybe do a left join with the _context.PhotoLikes.
Like this
feeds.GroupJoin(_context.PhotoLikes,
f => new { Id = f.Id, UserId = user.Id },
p => new { Id = p.ImageId, UserId = p.LikerId },
(f, p) => new { feed = f, photoLike = p })
.SelectMany(f => f.photoLike.DefaultIfEmpty(),
(f, p) => new FeedsForReturnDto
{
Id = f.feed.Id,
PhotoUrl = f.feed.photoUrl,
Username = f.feed.Username,
Description = f.feed.Description,
DateAdded = f.feed.DateAdded,
IsImage = f.feed.IsImage,
hasCurrentUserLiked = p != null,
Likes = feed.Likes
});
Just note that in this part
f => new { Id = f.Id, UserId = user.Id },
p => new { Id = p.ImageId, UserId = p.LikerId },
the datatypes of properties in both objects must match or it won't compile

(MVC) Trying to join a table it self by LinQ for display multiple language

I am trying to use LinQ to join a table itself, in order to display different columns in different session. In this case is when the LanguageId is "en" the "EnglishName" columns should be assigned to "Name". It always shows the error "cannot implicitly convert type...". I dont' know how to fix this code. Pls see the code bellow and help. Many tks.
MemberDao
public List<MemberViewModel> ListNewMember(int top, string languageId)
{
if (languageId == "en")
{
var model1 = from a in db.Members
join b in db.Members
on a.MemberId equals b.MemberId
select new MemberViewModel()
{
MemberId = a.MemberId,
Name = a.EnglishName,
Status = a.Status,
CreatedDate = a.CreatedDate
};
IQueryable<MemberViewModel> model2 = model1;
model2 = model2.Where(x => x.Status == true).OrderByDescending(x => x.CreatedDate).Take(top).ToList();
}
return db.Members.Where(x => x.Status == true).OrderByDescending(x => x.CreatedDate).Take(top).ToList();
}
MemberController
using GBVNET.Common;
using Model.Dao;
using Models.Dao;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace GBVNET.Controllers
{
public class MemberController : BaseClientController
{
//[ChildActionOnly]
//[OutputCache(Duration = 3600 * 24)]
public ActionResult Index()
{
var slideDao = new SlideDao();
var currentCulture = Session[CommonConstants.CurrentCulture].ToString();
ViewBag.ChildrenSlides = slideDao.ListChildrenSlide(1, currentCulture);
var categoryDao = new CategoryDao();
ViewBag.DocumentCategory = categoryDao.DocumentCategory(1, currentCulture);
ViewBag.ContactCategory = categoryDao.ContactCategory(1, currentCulture);
var model = new MemberDao().ListNewMember(5, currentCulture);
return View(model);
}
public ActionResult Detail(int id)
{
var slideDao = new SlideDao();
var currentCulture = Session[CommonConstants.CurrentCulture].ToString();
ViewBag.ChildrenSlides = slideDao.ListChildrenSlide(1, currentCulture);
var categoryDao = new CategoryDao();
ViewBag.DocumentCategory = categoryDao.DocumentCategory(1, currentCulture);
ViewBag.ContactCategory = categoryDao.ContactCategory(1, currentCulture);
var member = new MemberDao().ViewDetail(id);
return View(member);
}
}
}
This is the screenshot of the error: https://i.stack.imgur.com/q9qB2.jpg
I fixed them all by change the code as bellow:
MemberDao
public List<MemberViewModel> ListNewMember(int top, string languageId)
{
if (languageId == "en")
{
IEnumerable<MemberViewModel> model = from a in db.Members
join b in db.Members
on a.MemberId equals b.MemberId
select new MemberViewModel()
{
MemberId = a.MemberId,
Name = b.EnglishName,
Status = a.Status,
Logo = a.Logo,
Email = a.Email,
Address = a.Address,
Banner = a.Banner,
Facebook = a.Facebook,
Description = b.EnglishDescription
};
model = model.Where(x => x.Status == true).OrderByDescending(x => x.CreatedDate).Take(top).ToList();
return model.Where(x => x.Status == true).OrderByDescending(x => x.CreatedDate).Take(top).ToList();
}
else
{
IEnumerable<MemberViewModel> model = from a in db.Members
join b in db.Members
on a.MemberId equals b.MemberId
select new MemberViewModel()
{
MemberId = a.MemberId,
Name = b.Name,
Status = a.Status,
Logo = a.Logo,
Email = a.Email,
Address = a.Address,
Banner = a.Banner,
Facebook = a.Facebook,
Description = a.Description
};
model = model.Where(x => x.Status == true).OrderByDescending(x => x.CreatedDate).Take(top).ToList();
return model.Where(x => x.Status == true).OrderByDescending(x => x.CreatedDate).Take(top).ToList();
}
}

Mocking 2 or more DBContext calls to the same entity fails

I've got an MVC ASP.Net app using Entity Framework v6.0 with an Employee's table.
We're using a Code First approach with the standard Create (CRUD) method that has a EF lookup for existing employee's and also an EF lookup for employee CreatedBy/ModifiedBy fields. Trying to create mocks for both (EF object stubs) fails.
[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);
}
The problem is the SetAuditFields call and I need to mock db.Employees.AsNoTracking AsNoTracking for the Edit operation.
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;
}
}
So how do I mock db.Employees.AsNoTracking after initially mocking db.Employees?
The THESE TWO LINES COMMENTED OUT in the code below don't work and fail with:
"The member 'IQueryable.Provider' has not been implemented on type 'DbSet1Proxy' which inherits from 'DbSet1'
I also tried the mockContext.SetupSequence but I need to interchange between with AsNoTracking on and off. Surely there must be something I'm missing?
[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"]);
}
Here is the GetQueryableMockDbSet method:
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;
}
I ended up creating a chain of mocks using a counter as per https://stackoverflow.com/a/14368486/495455
int callCounter = 1;
mockContext.Setup(m => m.Employees)
.Returns(() =>
{
if (callCounter == 1)
{
callCounter++;
return employeeToEditMockCU;
}
else
{
return employeeMockCU;
}
});
Mocking using a SetupSequence doesn't work for me after the first mock. The db.Employee becomes null after the first call. So I dont use a SetupSequence:
mockContext.SetupSequence(x => x.Employees)
.Returns(employeeToEditMockCU)
.Returns(employeeMockCU);
Also to get around the AsNoTracking() I ended up fetching the record to update and saving it without using EntityState.Modified:
EF Update using EntityState.Modified
How to update record using Entity Framework 6?

Search stops working when adding a second filter query

I'm hoping you can help me with an issue I'm having. I'm new to ElasticSearch and am currently trying to implement a log search method that's going to be filtering through large amounts of logs. Currently, I can make it filter based on selected log types and that works fine, but as soon as I add the second filter, it no longer returns any results.
The only difference between the two filters I've added so far is, one is an int array, the other is a string list as seen in the current code, I've also tried converting it to a string array but to no help.
[Route("logs/search")]
[HttpGet]
public ActionResult Index(int[] logTypes, int entityType, string entitySource)
{
using (var db = new mtaEntities())
{
var targetSources = new List<string>();
switch (entityType)
{
// Username/charactername
case 0:
var characters = db.characters.Where(i => i.charactername.ToLower().Replace("_", " ") == entitySource.ToLower()).ToList();
accounts user = null;
if (characters.Any())
{
var accountId = characters.FirstOrDefault().account;
if (accountId != null)
{
user = db.accounts.FirstOrDefault(i => i.id == accountId);
characters.AddRange(db.characters.Where(i => i.account == user.id));
}
}
else
{
user = db.accounts.FirstOrDefault(i => i.username.ToLower() == entitySource.ToLower());
if (user != null)
{
characters.AddRange(db.characters.Where(i => i.account == user.id).ToList());
}
}
if (user != null)
{
targetSources.Add("AC-" + user.id);
foreach (var item in characters)
{
targetSources.Add("CH-" + item.id);
}
}
break;
}
var filters = new List<Func<QueryContainerDescriptor<Log>, QueryContainer>>();
filters.Add(fq => fq.Terms(te => te.Field(fi => fi.LogType).Terms(logTypes)));
filters.Add(fq => fq.Terms(te => te.Field(fi => fi.SourceUser).Terms(targetSources)));
var searchDescriptor = new SearchDescriptor<Log>();
searchDescriptor.Query(q => q.Bool(b => b.Filter(filters)));
var query = ElasticClient.Search<Log>(searchDescriptor);
var results = query.Documents;
return View(new Logs
{
IndexLastRebuilt = db.settings.FirstOrDefault(i => i.name == "elasticIndexLastRebuilt").value,
LogResults = results.ToList(),
LogTypes = db.logtypes.ToList()
});
}
}

Categories