relational data in asp.net mvc - json

I am getting 500 internal server error when method called for relational table data(Employee and department 0/1 to many ) to return as jsonresult.here is the method that gets error,
public JsonResult Index()
{
var employee = db.Employees.Include(x=>x.Department).ToList();
return Json(employee, JsonRequestBehavior.AllowGet);
}
but if i convert it as follows it works fine.
public JsonResult Index()
{ var emplist = db.Employees.ToList();
EmployeeViewModel emp = new EmployeeViewModel();
List<EmployeeViewModel> employee = emplist.Select(x => new EmployeeViewModel
{ EmployeeId = x.EmployeeId,
EmployeeName = x.EmployeeName,
DepartmentId = x.DepartmentId,
DepartmentName = x.Department.DepartmentName }).ToList();
return Json(employee, JsonRequestBehavior.AllowGet);
}
Is there any way I can get first method working..?

The error you are probably getting is due to MVC attempting to serialize your entity to pass to the client and the DB Context has fallen out of scope. (It is unclear how the DbContext is scoped with the code you have provided.) Serialization will iterate through every property in the entity, and for lazy-loaded references it will attempt to load them one by one. Even if the DbContext is scoped to the request and available this is very inefficient.
To avoid issues like this, simply do not pass EF entities between server and client. Nothing good will come of it. Pass a view model that represents just the data your view needs.
When you do:
var emplist = db.Employees.ToList();
// ^ Hits the database and loads ALL employees with all fields. (Does not load referenced data associated to employees, such as the departments.)
Employee emp = new Employee();
// ^ Does absolutely nothing for your cause.
List<Employee> employee = emplist.Select(x => new Employee
{ EmployeeId = x.EmployeeId,
EmployeeName = x.EmployeeName,
DepartmentId = x.DepartmentId,
DepartmentName = x.Department.DepartmentName }).ToList();
// ^ Selects 3 fields from each employee, then lazy-loads the department (works because the dbContext is in scope) and selects 1 field from the department. By using "new Employee" you are creating a POCO of the employee, not an EF proxy so the serializer will *not* attempt to resolve any dependencies.
return Json(employee, JsonRequestBehavior.AllowGet);
// ^ Serializes the POCO Employee object.
Instead, a better solution would be to declare an EmployeeViewModel that has EmployeeId, EmployeeName, DepartmentId, and DepartmentName, then use the following.
var employeeViewModels = db.Employees
.Select(x => new EmployeeViewModel
{
EmployeeId = x.EmployeeId,
EmployeeName = x.EmployeeName,
DepartmentId = x.Department.DepartmentId,
DepartmentName = x.Department.DepartmentName
}).ToList();
return Json(employeeViewModels, JsonRequestBehavior.AllowGet);
This will populate your view models with 1 hit to the database returning just the 4 fields you want to pass to the view rather than loading every field in the Employee plus an extra DB call to load the department. The view model is just a POCO so no weird behaviour around serialization. You can populate an Employee entity, however I'd recommend avoiding doing that because it can be confusing when working with an entity that may be an EF proxy (tripping up lazy loads) vs. a POCO entity which will be missing information and the EF context knows nothing about.

Related

Hibernate QuerySyntaxException, Table not mapped

I'm following this Tutorial. I have added another DAO where i'm retrieving the admin_roles table. The method looks like this
public List findAllAdminRoleByUserName(String userName) {
List<AdminRoles> users = new ArrayList<AdminRoles>();
Query hqlQuery = sessionFactory.getCurrentSession().createQuery("from admin_roles AdminRoles where AdminRoles.username = ?");
users = hqlQuery.setString(0, userName).list();
if (users.size() > 0) {
return users;
} else {
return null;
}
}
When I try to retrieve i'm getting the following error
HTTP Status 500 - Request processing failed; nested exception is org.hibernate.hql.internal.ast.QuerySyntaxException: admin_roles is not mapped [from admin_roles AdminRoles where AdminRoles.username = ?]
I am able to get values from the admin table mentioned in this tutorial, also I created some other tables from which i'm able to get values. But only this table is not being mapped. I also tried by changing the name of the table from "admin_roles" to adminroles(in the database and in code) I still get the same error.
The relevant class looks like this. Also the entity annotation is javax
#Entity
#Table(name = "admin_roles", uniqueConstraints = #UniqueConstraint(columnNames = { "role", "username" }))
public class AdminRoles{
Am I missing something? Thanks in advance
You're confusing tables and entities. Tables are a relational database concept. They're mapped to entities, which are Java classes. HQL uses entities. Always. Never tables.
BTW, the message is not "Table not mapped". It's "admin_roles is not mapped". And that's very different. HQL uses entities, so it expects admin_roles in your query to be a mapped entity. Not a table name. And you don't have any entity named admin_roles.
The query should be
select ar from AdminRoles ar where ar.username = ?
That assumes there is a mapped field/property named username in the AdminRoles entity class, of course.
You need to use the entity name in you query. Try like this:
"from AdminRoles AR where AR.username = ?"

Select query in hibernate annotations in spring mvc

Hi i am writing an spring mvc, employee application using mysql database,hibernate annotations and jsp . The database contains one table "Empdata" where empid is primary key.And there is a column "team" in "Empdata".I want to select employees in a specific team, example all the details of employees in "Team1".Here i can perform delete and edit operations in the application. For delete opertaion i am using
sessionfactory.getCurrentSession().createQuery("DELETE FROM Resource WHERE empid=" +resource.getEmpId()).executeUpdate();
query.I know the commandline query for select is
SELECT * FROM EmpData ERE EMPLTEAM ="Team1"
I want to know how to convert this query into hibernate.
please help,thanks in advance..
you can convert the query in the following way:
String sql = "select ed from EmpData ed where emplTeam = :emplTeam";
Query query = session.createQuery(sql);
query.setParameter("emplTeam ", team);
List<EmpData> empDataList = (List<EmpData>)query.list();
but you should have a class called EmpData containing a property emplTeam similar to the following:
#Entity
#Table(name = "EmpData")
class EmpData {
....
#Column(name = "EMPLTEAM")
private String emplTeam;
public String getEmplTeam() {
return emplTeam;
}
public void setEmplTeam(String emplTeam) {
this.emplTeam = emplTeam;
}
}
(I used annotations hibernate .. but you can do it the same way using .hbm.xml files)
For example
Query query = session.createQuery("from Student where name=:name");
query.setParameter("name", "Raj");
In your case i guess the Entity name is Empdata(The object that represent the table)
And the field in the object is team(That has getter and setter in object)
Query query = session.createQuery("from Empdata where team=:teamParam");
query.setParameter("teamParam", "team1");

Invalid object graph in Linq to SQL

I have a GiftCards table in my DBML that has a related property called Audit. The Audits are stored in a separate table. Each Audit has a related Person associated to it. There is also a Persons table. The relationships are set up and are valid in my DBML.
The problem is that when I instantiate a new Gift Card I also create a new related Audit in the OnCreated() method. But at the same time, I also create a related Person when I instantiate a new Audit. The Person is the current user. Actually the Audit's OnCreated method checks if the user already exists.
The problem is that when I instantiate a new gift Card, it also creates an associated Audit, which is fine, and the Audit creates an associated Person. But the Person already exists in the database. When I look at the data context's GetChangeSet(), it shows 3 inserts. The Persion should not show as an insert because he already exists in the database.
Here is how I implemented this. It is an MVC application where the Controller receives a gift card:
[HttpPost]
public ActionResult Save(GiftCardViewModel giftCard)
{
if (ModelState.IsValid)
{
GiftCard gc = GiftCardViewModel.Build(giftCard);
repository.InsertOrUpdate(gc);
repository.Save();
return View("Consult", new GiftCardViewModel(repository.Find(gc.GiftCardID)));
}
else
SetupContext();
return View("_Form", giftCard);
}
The Gift Card has:
partial class GiftCard
{
partial void OnCreated()
{
// Set up default audit.
this.Audit = new Audit();
}
}
The Audit class has:
partial void OnCreated()
{
// Setup timestamp
this.Timestamp = DateTime.Now;
this.Person = Person.GetPerson(Membership.GetUser().UserName);
}
And finally, my Person class has:
public static Person GetPerson(String username)
{
using (GiftCardDBDataContext database = new GiftCardDBDataContext())
{
// Try to get the person from database
Person person = database.Persons.SingleOrDefault(personData => SqlMethods.Like(personData.Username, username));
if (person == null)
{
person = new Person()
{
Username = username,
FullName = "Full name TBD"
};
database.Persons.InsertOnSubmit(person);
database.SubmitChanges();
}
// Return person data
return person;
}
}
When I create a new gift card, I always get an error saying that it's attempting to insert a duplicate person in the Persons table. I don't understand because my static class specifically checks if the Person already exists, if yes, I return the Person and I don't create a new one. Yet, the GetChangeSet() shows three inserts including the Person, which is wrong.
What am I doing wrong here?
I believe your issue here is that you're using multiple contexts. You have one being created by your repository, and another is created in the static method on your Person object. You also aren't making any effort to attach the Person created/retrieved from the other context to the context of your Audit class.
You should look at a single unit of work, a single DataContext class, and perform all your work in that.

LINQ 2 SQL Query ObjectDisposed Exception

This one i had today is a strange one.
I have this query in an assembly method.
public Order[] SelectAllOrders()
{
Order[] orders;
using (MyDataContext context = new MyDataContext())
{
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Order>(order => order.OrderDetails);
context.LoadOptions = dlo;
orders = context.Orders.Select(p => p).ToArray();
}
return orders;
}
Supposed i already called the ToArray() the SQL Command executed and gave me the objects i need and i give them to a new Order[] array this should not need the DataContext instance.
While im serializing the Order[] i get from the method return, serializer tries to access the DataContext again and i get an exception that cannot access disposed object.
Tried without the using() statement and works like it should. But, why i get this behavior?
Anyone could give an explanation why deferred loading still remains while I'm calling .ToArray() and assigning new variable with the contents?
The Select(p=>p) achieves very little; you might as well just call:
orders = context.Orders.ToArray();
Re the problem - I would guess that either OrderDetails hasn't really loaded, or it is trying to load some other data lazily. I would suggest investigating by (in a dev session):
Order[] orders;
using (MyDataContext context = new MyDataContext())
{
context.Log = Console.Out; // show me
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Order>(order => order.OrderDetails);
context.LoadOptions = dlo;
Console.WriteLine("> Calling ToArray");
orders = context.Orders.ToArray();
Console.WriteLine("> ToArray complete");
// TODO: your extra code that causes serialziation, probably
// involving `DataContractSerializer`
Console.WriteLine("> Calling Dispose");
}
With this, you should be able to see any extra database trips that are happning after the ToArray but before the Dispose(). The point being: this data is needed for serialization, so either a: ensure it gets loaded, or b: exclude it from serialization.

What's the best way to save a one-to-many relationship in Linq2Sql?

I'm trying to figure out the best way to save a simple one-to-many relationship in Linq2Sql.
Lets assume we have the following POCO model (pseduo code btw):
Person has zero to many Vechicles.
class Person
{
IList<Vehicle> Vehicle;
}
class Vehicle
{
string Name;
string Colour;
}
Now, when i save a Person, i pass that poco object to the repository code (which happens to be L2S). I can save the person object fine. I usually do this.
using (Db db = new Db())
{
var newPerson = db.People.SingleOrDefault(p => p.Id == person.Id) ?? new SqlContext.Person();
// Left to right stuff.
newPerson.Name = person.Name;
newPerson.Age = person.Age;
if (newPerson.Id <= 0)
db.People.InsertOnSubmit(newPerson);
db.SubmitChanges();
}
i'm not sure where and how i should handle the list of vehicles the person might have? any suggestions?
using (Db db = new Db())
{
var newPerson = db.People.SingleOrDefault(p => p.Id == person.Id) ?? new SqlContext.Person();
// Left to right stuff.
newPerson.Name = person.Name;
newPerson.Age = person.Age;
// add vehicles.
Vehicle firstV = new Vehicle();
firstV.Name = "some name";
firstV.Person = newPerson; // need to do this to set the person Id on the vehicle.
newPerson.Vehicle.Add(firstV);
// now when you save the Person it should save the Vehicle list
// if you set Cascade save update on the list. (not sure how to do that in L2S
if (newPerson.Id <= 0)
db.People.InsertOnSubmit(newPerson);
db.SubmitChanges();
}
Now you may choose to construct the list of vehicles at another level , with the data that's coming from the interface.
But you need to remember that it's not enough to add the Vehicle to the list on the Person object , you also need to set the vehicles Person property to the person that has the vehicles.
Observation I'm not sure about this but when you do db.People.SingleOrDefault you might be loading the whole People table in memory . That's not something you want to do. Corrected by Slace in the comments.
All you need to do is ensure that there are the appropriate relationships set up within the database.
If your Vehicle table has a PersonId and there is a foreign key between them when you add them to the DBML Linq to SQL will detect that there is a relationship between them and create a Table<T> representation of the relationship.