asp.net mvc 5 Dapper Json is mapping the whole model class - json

I am using Dapper in my ASP.NET MVC 5 application and in my query I only want 2 fields to return but the Json returns all of the fields. This is my model
public class thread
{
[Key]
public int id { get; set; }
public int? profileID { get; set; }
public int numberkeeper { get; set; }
public int? photocount { get; set; }
}
This is my controller..
[ResponseType(typeof(thread))]
public IHttpActionResult Getstream()
{
string Connectionstring = ConfigurationManager.ConnectionStrings["db"].ConnectionString;
using (System.Data.SqlClient.SqlConnection sqlConnection = new System.Data.SqlClient.SqlConnection(Connectionstring))
{
sqlConnection.Open();
var statevi = sqlConnection.Query<thread>("Select top 5 id,numberkeeper from threads").ToList();
if (statevi == null)
{
return NotFound();
}
return Ok(statevi);
}
}
That code returns Json as it is using .Net Web API,as you can see from the query I only want 2 fields returned. When I run it and see the Json it displays all fields (4) and off course the 2 fields not selected show up as null . I wanted so that the Json only shows the returnn of id and numberkeeper

Create a View Model class:
public class ThreadViewModel
{
public int id { get; set; }
public int numberkeeper { get; set; }
}
Let Dapper know you want it to create the ThreadViewModel for you:
var statevi = sqlConnection.Query<ThreadViewModel>("Select top 5 id,numberkeeper from threads").ToList();
This way you both query the database for the relevant properties and return just them to the client (without Dapper creating the full object with nulls).

If you create a new model that exposes the only two members that you want to render, that will prevent Web API from returning back additional JSON.
You could also convert the data after loading it into a new anonymous model using LINQ.
return Ok(statevi.Select(s => new { s.id, s.numberkeeper }));
If you want to keep the same model, but suppress null valued members Web API allows you to configure the JSON formatting to exclude null properties.
config.Formatters.JsonFormatter.SerializerSettings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
};

If you want to use 2 or selected rows from query then you can use query method and extension method...
1. LINQ query method
using (System.Data.SqlClient.SqlConnection sqlConnection = new System.Data.SqlClient.SqlConnection(Connectionstring))
{
sqlConnection.Open();
var statevi = sqlConnection.Query<thread>("Select top 5 id,numberkeeper from threads").ToList();
if (statevi == null)
{
return NotFound();
}
var result = (from d in statevi
select new { d.id, d.numberkeeper }).ToList();
return Ok(result);
}
Extension Method: change this syntax to result of query method of above
var result = query.Select(d => new { d.Id, d.Title }).ToList();
both will give result same.
let me tell if it is working fine for your project or not.

Related

MySQL and EF Core 6 error The LINQ expression could not be translated

I recently updated our project from EF Core 2.2.6 to 6.x (along with and upgrade from .NET core 3.1 to .NET 6) and now I'm get errors like the one stated in the title whenever the query gets even a little complicated. One of those cases is when you add a GroupBy clause. Below is an example of a failing query.
_context.MyTable
.Where(a => a.Name.Contains("service"))
.GroupBy(ss => ss.IsServiceSpecific)
The entire error is:
The LINQ expression 'DbSet< MyTable >()
.Where(a => a.Name.Contains("service"))
.GroupBy(ss => ss.IsServiceSpecific)' could not be translated. Either rewrite the query in a form that can be translated, or switch
to client evaluation explicitly by inserting a call to 'AsEnumerable',
'AsAsyncEnumerable', 'ToList', or 'ToListAsync'
The setup at this MySQL::Entity Framework Core Support URL is exactly what I did (there are only two steps to set it up). My DI config looks like this:
builder.Services.AddEntityFrameworkMySQL()
.AddDbContext<MydbContext>(options =>
{
options.UseMySQL(builder.Configuration.GetConnectionString("DefaultConnection"));
});
It will execute simple queries but more complex ones always generate this error. It says to rewrite the query and force client side evaluation by using AsEnumerable or ToList but I don't want to drag all that data to the client and I expect that a simple group by can be translated and handled server side.
I did find one article that talks about this problem but I'm not getting if it's suggesting an actual solution.
This shouldn't be this hard and I feel like I'm missing something simple.
Model
internal class Post
{
public int PostId { get; set; }
public string? Title { get; set; }
public string? Content { get; set; }
public int BlogId { get; set; }
}
DBContext
internal class BloggingContext : DbContext
{
public DbSet<Post>? Posts { get; set; }
public string DbPath { get; }
public BloggingContext()
{
var path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
DbPath = $"{path}{Path.DirectorySeparatorChar}blogging.db";
}
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseSqlite($"Data Source={DbPath}");
}
Main
internal class Program
{
static void Main(string[] args)
{
using (var db = new BloggingContext())
{
var posts = db.Posts.Where(s => s.Title.Contains("Hello")).GroupBy(g => g.BlogId == 1994).Select(s => new { Key = s.Key, Counts = s.Count() }).ToList();
foreach (var p in posts)
{
Console.WriteLine(p);
}
}
}
}
Conclusion: You might add Select statement after GroupBy.

Proper way to return JSON list in Web API with MVC and partial model

I am trying to use Web API to grab certain fields from my MVC controller. I can't seem to match the right type with the right list. I am fine with converting everything to string.
I either get an error in code (can not convert types), or if I get it to compile, I get this error:
"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'."
From other similar posts, people responded with how to create a list, but not with the declaration of the return value of the Get. Please include both.
Also I would prefer not to add additional controllers as I need to do this on a number of my models.
Here is my code--note you can see I tried a number of different ways:
public class APICLIENTsController : ApiController
{
private ApplicationDbContext db = new ApplicationDbContext();
// GET api/<controller>
public IEnumerable<string> Get()
//public IEnumerable<CLIENT> Get()
{
//return db.CLIENTs.OrderBy(x => x.CLIENTNAME).ToList();
string[] listOfUsers = db.CLIENTs.OrderBy(x => x.CLIENTNAME).Select(r => new
{
ID = r.CLIENTID.ToString(),
NAME = r.CLIENTNAME
});
return listOfUsers.ToList();
//return db.CLIENTs.Select(x => new { x.CLIENTNAME }).ToArray();
}
If you want to return JSON use the
JsonResult
type.
public JsonResult Get()
{
//return db.CLIENTs.OrderBy(x => x.CLIENTNAME).ToList();
string[] listOfUsers = db.CLIENTs.OrderBy(x => x.CLIENTNAME).Select(r => new
{
ID = r.CLIENTID.ToString(),
NAME = r.CLIENTNAME
});
return Json(listOfUsers.ToList(), JsonRequestBehavior.AllowGet);
}
Your query is returning a collection of anonymous objects, not string[] so it will throw an exception. Even if you were to generate string[] by concatenating the CLIENTID and CLIENTNAME properties, it would be a little use to the client.
Create a model to represent what you need to return to the view
public class ClientVM
{
public int ID { get; set; }
public string Name { get; set; }
}
and modify your method to
public IEnumerable<ClientVM> Get()
{
IEnumerable<ClientVM> model = db.CLIENTs.OrderBy(x => x.CLIENTNAME).Select(r => new ClientVM
{
ID = r.CLIENTID,
Name = r.CLIENTNAME
});
return model;
}
Side note: depending on how your calling and consuming this in the client, you may need to change the Content-Type to specifically return json (refer these answers for more detail)

How to show foreign table values in ASP.net MVC Core in ViewComponents

I have a modal like below,
public int userId{ get; set; }
public string userName{ get; set; }
public int categoryId { get; set; }
[ForeignKey("categoryId")]
public virtual category categories { get; set; }
and I am using ViewComponents and this is my Invoke method;
public IViewComponentResult Invoke()
{
var users = db.Users.OrderByDescending(x => x.userId);
return View(users);
}
and this is my View Component's cshtml page;
#model IEnumerable<users>
#foreach (var user in Model)
{
<text>
{ label: "#user.userName - #user.categories.categoryName},
</text>
}
but for how, I cannot get the value of category name. When i do, i get 500 internal error.
So how can i get foreign table value inside View Component in ASP.NET MVC CORE.
Thanks.
ok do one thing create a viewModel and mention all the columns you required in that ,after that put a join between User and Category table and pass the data like below.
Dummy Query below this way your code surely work..just make changes according to your columns and needs
var query = from book in context.BOOKs
join publisher in context.Publishers
on book.PublisherId equals publisher.Id
select new BookModel {
Id = book.Id,Title=book.Title,
PublisherName=publisher.Name,Auther = book.Auther,
Year = book.Year,Price=book.Price
};

MVC repository and interface returning Json

I'm new at MVC and can't get this to work. I basically have a Users class, a UserRepository, and a IUser interface.
This is my code:
public class Users
{
public string UserName { get; set; }
public string Department { get; set; }
public string UserType { get; set; }
}
public class UsersRepository : TimeAttendanceMVC.Models.IUsers
{
public Users Return_UserName_Dept()
{
Users U = new Users();
List<Users> LoggedInUser = new List<Users>();
U.UserName = "TestUser";
U.Department = "Finance";
U.UserType = "Administrator";
LoggedInUser.Add(U);
//string json = JsonConvert.SerializeObject(LoggedInUser, Formatting.Indented);
//return json;
return Json(LoggedInUser.ToArray(), JsonRequestBehavior.AllowGet);
}
}
namespace TimeAttendanceMVC.Models
{
public class IUsers
{
List<Users> Return_UserName_Dept();
}
}
There are a few errors that I get. In UsersRepository.cs where i'm returning Json, the error says that "The name Json does not exist in the current context". The error from IUsers.cs is that "Return_UserName_Dept() must declare a body because it is not marked abstract...".
Can anybody please help me with this. I just don't know how this is supposed to work and i'm trying to learn MVC by working on this application. It's actually the FullCalendar application found here - link to FullCalendar. I'm trying to turn it into an MVC application.
EDIT:
Maybe I need to do this:
public JsonResult Return_UserName_Dept()
instead of public Users Return_UserName_Dept()
You should be doing this on your controller in some method which returns a json action (jsonresult). The repository should be returning your data only and all the operations you need to do, whether you're converting data to json or any other logic should happen at the controller or at some helper class which would be called by the controller..
Edit:
In order to have a method which returns a JsonResult, you need to have a reference to System.Web.Mvc.ActionResult and since the repository is usually at the model, you won't have this reference.. another thing is that you might be breaking your design the logic should be available at the controller for what you want
Edit 2:
The code below is from an old post you can see here. Note how the action PopulateDetails gets the user object from the repository and that's all the repository does.. the actual logic is happening inside this method, such as populate the rest of the UserModel class, and then it returns the JsonResult:
public JsonResult PopulateDetails(UserModel model)
{
UserResultModel userResultModel = new UserResultModel();
if (String.IsNullOrEmpty(model.UserId))
{
userResultModel.Message = "UserId can not be blank";
return Json(userResultModel);
}
User user = _userRepository.GetUser(model.UserId);
if (user == null)
{
userResultModel.Message = String.Format("No UserId found for {0}", model.UserId);
return Json(userResultModel);
}
userResultModel.LastName = user.LastName;
userResultModel.FirstName = user.FirstName;
userResultModel.Message = String.Empty; //success message is empty in this case
return Json(userResultModel);
}

asp.net mvc json result format

public class JsonCategoriesDisplay
{
public JsonCategoriesDisplay() { }
public int CategoryID { set; get; }
public string CategoryTitle { set; get; }
}
public class ArticleCategoryRepository
{
private DB db = new DB();
public IQueryable<JsonCategoriesDisplay> JsonFindAllCategories()
{
var result = from c in db.ArticleCategories
select new JsonCategoriesDisplay
{
CategoryID = c.CategoryID,
CategoryTitle = c.Title
};
return result;
}
....
}
public class ArticleController : Controller
{
ArticleRepository articleRepository = new ArticleRepository();
ArticleCategoryRepository articleCategoryRepository = new ArticleCategoryRepository();
public string Categories()
{
var jsonCats = articleCategoryRepository.JsonFindAllCategories().ToList();
//return Json(jsonCats, JsonRequestBehavior.AllowGet);
return new JavaScriptSerializer().Serialize(new { jsonCats});
}
}
This results with following:
{"jsonCats":[{"CategoryID":2,"CategoryTitle":"Politika"},{"CategoryID":3,"CategoryTitle":"Informatika"},{"CategoryID":4,"CategoryTitle":"Nova
kategorija"},{"CategoryID":5,"CategoryTitle":"Testna
kategorija"}]}
If I use line that is commented and place JsonResult instead of returning string, I get following result:<
[{"CategoryID":2,"CategoryTitle":"Politika"},{"CategoryID":3,"CategoryTitle":"Informatika"},{"CategoryID":4,"CategoryTitle":"Nova
kategorija"},{"CategoryID":5,"CategoryTitle":"Testna
kategorija"}]
But, I need result to be formatted like this:
{'2':'Politika','3':'Informatika','4':'Nova
kateorija','5':'Testna kategorija'}
Is there a simple way to accomplish this or I will need to hardcode result?
Have a look at the Json.Net library
The Json.NET library makes working
with JavaScript and JSON formatted
data in .NET simple. Quickly read and
write JSON using the JsonReader and
JsonWriter or serialize your .NET
objects with a single method call
using the JsonSerializer.
I have successfully used it within a .net mvc project.
ile,
you really should look at the json.net lib, i was in a similar dilemma recently with json/jquery and mvc and tried my own hand-rolled version but hit the many limitations in my own implemetation. the newton json lib is quite simply a no-brainer - simple to use and always being updated. the current version works fantastically with nested structures, thus making that particular json formatting issue a non-issue.
give it a look, will take you 15 mins to get to grips with.
Try returning it as an Array, Also if you return a JsonResult you can save alot of code (looks like you were attempting to get the formatting you wanted)
public class ArticleController : Controller
{
ArticleRepository articleRepository = new ArticleRepository();
ArticleCategoryRepository articleCategoryRepository = new ArticleCategoryRepository();
public JsonResult Categories()
{
var jsonCats = articleCategoryRepository.JsonFindAllCategories().ToArray();
return Json(jsonCats, JsonRequestBehavior.AllowGet);
}
}
in my test I got a result of
[{"Id":1,"Name":"Cat 1"},{"Id":2,"Name":"Cat 2"}]