I ran into an annoying issue recently. I'm going to simplify my datamodel here, but the principle is just the same. I have a class "User". In that class I have a property that is a list of objects the user owns. I also have this class "object". Because every "object" has an owner, it has a property of type "User", which links to its owner. Now, what I'm trying to do is basically this
return Json(myUser,JsonRequestBehavior.AllowGet);
When I load the page, it takes like 30 seconds and then I get the error "RecursionLimit exceeded".
I guess this is because the objects are linking to each other. Now my question is, how can I tell "Json" that it shouldn't go deeper then 1 level of objects to avoid this?
myUser is probably a type generated by EntityFramework.
When you return Json, the framework is going to prepare each property in essence firing off SQL command to lazy-load all the data.
Instead, you should prepare a ViewModel class with concrete properties not attached to EntityFramework and prepare that object as deep as you want it to go.
It might happen when your object has some properties of itself. for example.
public object Employee()
{
string ID {get; set;}
string Name {get; set;}
int Age {get; set;}
Employee Boss{get; set;} //<-- here
}
var employee = new Employee();
return Json(employee,JsonRequestBehavior.AllowGet); //The Boss property will cause "RecursionLimit exceeded".
To avoid that. you can do something like that:
var employee = new Employee();
var prepareForJson = new {
ID = employee.ID,
Name = employee.Name,
Age = employee.Age,
Boss = employee.Boss.ID
};
return Json(prepareForJson , JsonRequestBehavior.AllowGet);
You can configure recursion depth through web.config
http://msdn.microsoft.com/en-us/library/bb763183.aspx
but you probably just want to sort out your model not to have recursion in the first place. Think how much data is needed in your current situation and return just that.
I think Edison Chuang is the answer for the vast majority of cases (mapping data models to some service models that do not have those navigation properties that will most certainly cause loops during the serialization).
However, since most of the service models will share many of the properties of the data models (EF models), AutoMapper can be used, greatly simplifying code especially for objects with many properties. E.g.:
// set up map
cfg.CreateMap<Employee, EmployeeSm>();
// use the map
var sm = Mapper.Map<EmployeeSm>(employee);
// this can be also set up during mapping configuration phase
sm.Boss = employee.Boss.ID;
For those rare cases when serialization depth goes beyond the default 100, you can either increase this limit or use Json.NET to serialize your objects.
Related
i have the following model:
public partial class location
{
public int Id { get; set; }
public double Lat { get; set; }
public double Long { get; set; }
public virtual ICollection<localserver> localserver { get; set; }
}
When, in a controller, i do:
List<location> l = db.location.ToList();
i get also the localserver object. How, in LINQ, get only the property of location (Id, Lat and Long) without using the Select argument in linq?
The way to extract part of an object is to project it to a new form, which is what .Select() is for:
var result = db.location
.Select(x => new
{
Id = x.Id,
Lat = x.Lat,
Long = x.Long
})
.ToList();
Now, you've specifically asked how to do this without using .Select(), so... really, the answer is "you don't". You've ruled out the tool that's specifically designed for the scenario you're presenting, so no useful answer remains.
To address the intent of your question, however, I'm going to make a guess that you don't want to load the collection of localserver objects, perhaps because it's large and uses a lot of memory. To solve that problem, I would suggest the following:
If you're using Entity Framework Code First, check your cascade options when creating the database (if you're setting any).
Check that the collection is declared as virtual (you've shown it as such here but check the actual source)
Check that you have lazy-loading enabled, by setting myContext.ContextOptions.LazyLoadingEnabled = true; at some point
This should allow the application to lazy-load that property, which means that the contents of that localserver property will only be retrieved from the database and loaded into memory when they're actually needed. If you don't ever access it, it won't be loaded and won't take up any memory.
When you are getting Location list entity is not pulling Localserver object data, the thing that entity framework has feature called lazy loading. Lazy loading means you can get associated object at any time you need, no need write one more separate linq query to get. This will pull data from associated object only when you call them inside the code, then entity framework will make one more call to database to load that associated object data.
So just go with your code, but if you want some selected columns from Location object itself than you have write Select and supply column names.
Let's say I have two classes like below:
public class Class1
{
....
public int CityId {get;set;}
public string CityName {get;set;}
public ObjectId _id {get;set;}
}
public class Class2 : Class1
{
public string OrderId {get;set;}
}
collUser.Update(
Query.EQ("_id", model._id),
Update.Replace(model));
when I use objects type of Class2 , update works in a normal way.
but when I use objects type of Class1 , update deletes OrderId field in the record.
I assume it replaces all record ( document) in the collection.
Is there a way to avoid this ? or Is there an easy way than using Update.Set as below ?
Update.Set("fieldName",value).Set("fieldName2",value2)
I mean , I just want to update the fields if that object (Class1 or Class2) owns the property wthout deleting the rest fields.
I'm not sure how you're trying to accomplish this, but it should already work the way you expect. I've done this:
var collection = db.GetCollection<Class1>("stuff");
var class2 = new Class2 {CityName = "Toronto", OrderId = "12345"};
collection.Save(class2);
var retrieved = collection.FindOne();
collection.Save(retrieved);
retrieved = collection.FindOne();
Console.WriteLine("Object deserialized as type {0}", retrieved.GetClass().Name);
The retrieved object is actually Class2 and OrderId is preserved (no data loss). I think this is probably the most expected behavior. Mongo accomplishes this by including a type discriminator. This is basically a hint for itself so it knows what type to deserialize the document to. If you save an Employee object into a Person typed collection, mongo knows to include the type discriminator because Employee is a sub-type of Person.
To stay out of trouble, follow one simple rule: strongly type your collections to one single type. If you have a collection that contains Employees and Managers, you should only ever create db.GetCollection<Person>("people"). That way, Mongo can do it's work properly. Once you start doing both db.GetCollection<Employee>("people") and db.GetCollection<Manager>("people") you get into serious trouble (and the data loss issues you discovered).
If you're still not satisfied with this answer, you might like the idea of directly updating documents. MongoDB is actually well known for it's ability to quickly update documents. I highly recommend that you look at this section, even if you're satisfied with my first suggestion.
I have two class like this:
public Class Company
{
public IList<Employee> Employees;
}
public Class Employee
{
public Company WorkPlace;
}
when I want to save an object of class Company:
MongoDatabase Database = MongoServer.GetDatabase("db");
var workPlace = new Company();
var employee = new Employee { WorkPalce = workPlace}
workPlace.Employees = new List<Employee>{ employee };
Database.GetCollection<Company>("company").Save(workPlace);
StackOverFlow Exception will be thrown.
This is being caused because you have a cycle formed by the classes referencing each other, clearly the driver is not equipped to handle this and I am not convinced it should.
You need to decide how you want this data modelled in the database.
If you are having two collections, one of companies and one of employees, then at a data level you should be just including id's for the references.
If you are just having a single collection of companies though, then you just need to change the employee class to reference back to the company with an id instead of an object reference.
This only needs to happen in the database though, you can extend your model in your c# code to automatically add the object reference or lazy load it etc (avoiding select N+1 issues as you do) depending on what is right for the situation.
This question was also asked on Google groups:
https://groups.google.com/group/mongodb-user/browse_thread/thread/4ea7c6885bfb4f33#
and there are some additional answers there.
I suggest, try kundera. It should be able to handle such case for Mongo.
https://github.com/impetus-opensource/Kundera
take a look at kundera-examples at
git#github.com:impetus-opensource/Kundera-Examples.git
I posted this:
Object depending on another object - when to load its properties
After reading this and researching some more I've come to realize that lazy loading would be ideal for my situation. However, some background info. The class I posted Department gets its properties data from a database (Sql Server 2k5). Its your typical setup:
Front End->BOL->DAL
So I wanted to keep my Department class basically just hold information pertinent to it. I did not / do not want to expose my business object class to this class. So how would I fill my department object without having to make a call to my business object layer.
I think code would help:
public class Employee
{
public int ID { get; set; }
public string FirstName { get; set; }
public Department d { get; set; } //todo: implement lazy load in get.
public Employee(int ID, string FirstName)
{
this.ID = ID;
this.FirstName = FirstName;
}
}
class Department
{
public string DepartmentID { get; set;}
public string CostCenter { get; set; }
public bool hasManager { get; set; }
//more code
//constructor for department
}
And then say my BOL is used to call my DAL to do something like:
//some bol class that simply calls the data access layer class
DAL.GetDepartments("SomeDepartment");
And the DAL does some code to return some data to fill a department object...
However if I lazy load my get property for the department then it would need to know about my BOL so I'd have to add a using statement to include that class as well. That can't be the right way to do this...Any tips or pointers?
If you really want to do lazy loading of components, take a look at some ORM like NHibernate, EF4, etc.
To create your own lazy load solution is not a trivial task and it involves some complex concepts like dynamic proxing, maybe IL generation and other advanced topics.
Anyway, regarding your question on dependencies and use or not use your BOL from your DAL, check if you can apply dependency inversion.
In my current project, almost all my domain business objects have at least two constructors. (1) takes an id for that object, so that it can self-construct, pulling data from the db itself. The other constructor (2) takes the data entity required for that domain object to function. In this way, I can eager load or lazy load, whichever is best at the time.
So, if someone calls your Employee business object Department property, the property could check if it already had that. If not, you could get the DepartmentID from the employee data, instantiate a department, and (store if and) return it. In this way, it's easy to get whatever domain objects you need.
But you still want the eager-loading option there. Let's say you have a Department business object, with an Employees property to return a List(Of Employee). The Employees property would directly get the data from the database, and instantiate each Employee using the data constructor. So you'd have your cool Employee business objects, 80 of them, but with just one data query.
And then to take it up a notch, your objects could accept multi-layer data. For example, you can construct an Employee with an Employee entity from the DAL, that also includes the data for the Department, Supervisor, etc. The "ID" constructor could also get this data from the get-go.
Eventually you'll have some decisions to make about what to pre-load and what to lazy-load. For example, maybe 90% of the time when you construct an Employee, you also need the Department data. Then you might decide to just get the Department data when you construct an employee using the EmployeeID constructor. But the, say, supervisor data is only used 8% of the time. You might decide to always lazy load that.
The simple answer is, obviously, it can't be done. Either you're going to have to let your business objects know about your data layer (make sure to use DI if you go this route) or you can't lazy load from within the business class. A happy medium might be to create a service class that knows about both DAL workings and your business layer and knows how to load and create business objects. Of course, as Juanma stated, ORMs were built to do this kind of thing.
Let's say I've got the following ActiveRecord class:
[ActiveRecord]
public class Account
{
...
[BelongsTo("CustomerId")]
public Customer Customer { get; set; }
}
Currently, to set the value of the CustomerId field I have to get the entire Customer object from the database and assign it to the Account:
Customer customer = Customer.FindById(1);
account.Customer = customer;
This isn't very efficient. I'd rather set the value of CustomerId field directly without round-tripping the database, e.g.
account.CustomerId = 1;
What's the correct way to do this?
I don't know how Castle ActiveRecord uses NHibernate to load objects from the database (using ISession.Get or ISession.Load?), but I know that the following can be done with NHibernate:
var ghostCustomer = session.Load<Customer>(customerId);
var account = session.Get<Account>(accountId);
account.Customer = ghostCustomer;
Here, ghostCustomer will be an unitialized proxy object, whose fields will be lazy loaded the first time they are accessed. But since we only use it to assign the customer relation on the account, it will never actually be loaded.
Thus, the only database access in this example will happen when loading the account and afterwards when the session is flushed and the account must be updated.
It depends, really. You can implement caching to lessen the burden of obtaining data that might not change too often like customers. Beware this might be premature optimisation though.
I agree with Neil, but if you really want this, you can do it with IQuery.ExecuteUpdate()
You can implement MK8k's solution in ActiveRecord. It would look like this:
using (new SessionScope()) {
var ghostCustomer = Customer.Find(customerId);
var account = Account.TryFind(accountId);
account.Customer = ghostCustomer;
}
Two important points:
The Customer.Find must be in a SessionScope. The Find method checks and will fully load your object if a SessionScope is not defined.
The Customer class must be defined as lazy. NHibernate will not use a proxy for a non-lazy class.