LINQ 2 SQL Query ObjectDisposed Exception - linq-to-sql

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.

Related

relational data in asp.net mvc

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.

LINQ To SQL does not work when adding new object

I use the following code to insert a new record to my Users table:
public bool CreateUser(User obj)
{
obj.Id = Guid.NewGuid();
using (_db = new CMSDataContext())
{
obj.SiteId = SiteID;
_db.Users.InsertOnSubmit(obj);
_db.SubmitChanges();
}
return true;
}
I do not get any errors, and everything seems fine. I can read a record from database with same DataContext. But after the above method runs completely, I see nothing new in my Users table. Why?
Is the id column truly a PK in the sql server database?

Why LINQ 2 SQL when I Dispose the context tries to get child relationships?

I use LINQ 2 SQL in one of my projects and i have numerous relationships Customer -> Documents1, Documents2, Documents3, Address, Invoices etc....
When using the LoadWith(p => p.Documents1)...etc
I have performance issues, imagine 2000 customers with all these numerous relationships loaded in List in memory!
The other way around Document -> Customer its not so much an issue as the relationship its light.
So i try to remove all the LoadWith and just leave the Customer -> Address relationship.
Now if i go and open a Document1 and then open my Customers i get an object disposed exception when i serialize my Customers. The serialize method basically throws this exception.
The serialize Method:
public static T CloneObjectGraph<T>(this T obj) where T : class
{
var serializer = new DataContractSerializer(typeof(T), null, int.MaxValue, false, true, null);
using (var ms = new System.IO.MemoryStream())
{
serializer.WriteObject(ms, obj);
ms.Position = 0;
return (T)serializer.ReadObject(ms);
}
}
The Method i get the Customers:
public List<Customer> GetCustomers()
{
using (MyDataContext db = new MyDataContext(MyDataContextManager.ConnectionString))
{
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Customer>(p => p.Address);
dlo.LoadWith<Customer>(p => p.Documents1);
dlo.LoadWith<Customer>(p => p.Documents2);
dlo.LoadWith<Customer>(p => p.Documents3);
dlo.LoadWith<Customer>(p => p.Documents4);
dlo.LoadWith<Customer>(p => p.Documents5);
dlo.LoadWith<Customer>(p => p.Documents6);
dlo.LoadWith<Customer>(p => p.Documents7);
dlo.LoadWith<Customer>(p => p.Documents8);
dlo.LoadWith<Customer>(p => p.Documents9);
dlo.LoadWith<Customer>(p => p.Documents10);
dlo.LoadWith<Customer>(p => p.Documents11);
db.LoadOptions = dlo;
return db.Customers.ToList();
}
}
I want to remove all the LoadWith except Address relationship.
I hate when this error is not reproduce always but in some cases i couldn't find.
I could guess the DataContractSerializer constructor for a change but i cant get it right.
Any help appreciated!
Your error is occurring because your clone method is going to attempt to access all of the child properties of your object. When you have the LoadWith<>() statements, those child properties are already retrieved from the database and available in memory. When you remove the LoadWith<>() statements, the properties will attempt to Lazy Load the objects from the database. Because you've already closed the database connection, those properties cannot be loaded (and you get the error).
The solution depends on what you are attempting to accomplish by performing a deep copy of the objects; If that deep copy actually does need to have the child properties (DocumentsXX), then you either have to leave the LoadWith<>() statements or you need the database connection to stay open during the process (of the two, leaving the LoadWith<>() statements is probably the better option because it minimizes the accesses to the DB and ends up using the same amount of memory anyway). If the deep copy really doesn't need to include those properties, then you need to replace the current deep clone process with on that can ignore those properties (either a manually created deep clone or a customized serialization process would work).

Foreign keys cause more queries?

I have 2 objects - Order and Product. On the Order only productID is saved and when I view orders I want to see the product name. According to ScuttGu blog this is easily done by using a template field with Eval("Product.ProductName"). However, when reviewing the actual queries I see that for each order a separate query is made.
It doesn't sould right to me because for many rows and/or foreign keys many additional queries will be made. Doesn't it make the whole this too inefficient (i.e. why linq doesn't use a join)?
Thanks
That is because your products are lazy loaded - that is they are loaded when needed.
You can DataLoadOptions to set your fetchingstrategy, and load the products with your order:
MyDataContext db = new MyDataContext();
DataLoadOptions options = new DataLoadOptions();
options.LoadWith<Order>(order => order.Product);
db.LoadOptions = options;
var orders = from c in db.Orders
If you don't like the pr. datacontext specification of loadoptions you do something like this (not testet):
MyDataContext db = new MyDataContext();
db.Orders
.Select(o => new { Order = o, Products = o.Products})
.ToList()
.Select(x => x.Order)
.ToList();
I have implemented something like this guys fethingstrategies, which works out nicely with my repositories and the specification pattern.
This happens because at the point that Eval has run, the query already has, without said join.
When you're fetching the query you can use DataLoadOptions to include this using the .LoadWith() method:
var dlo = new DataLoadOptions();
dlo.LoadWith<Order>(o => o.Product);
var dc = new DataContext();
dc.LoadOptions = dlo;
var orders = from dc.Orders select o;

Can I update 1 object only with Linq to SQL?

Its a simple question, but I'm not aware of the answer and I couldn't get it to work.
Can I update only one entity on the entire DataContext? Or should I follow plain ADO.NET for this operation only?
Edit:
public MyObject GetMyObjectById(int selectedId)
{
DataContext db = _dbManager.GetContext();
return db.MyObject.SingleOrDefault(p => p.Id == selectedId);
}
I am getting an object with the above query...
I am querying then for an integer...on another table/object
public int GetMyInteger()
{
DataContext db = _dbManager.GetContext();
return db.MyAnotherObject.FirstOrDefault().MyInteger;
}
Everything is fine for all my operations...but now i just want to update only the integer i got from the database...
public void SetMyInteger(int updInteger)
{
DataContext db = new DataContext(ConnectionString);
MyAnotherObject theEntity = db.MyAnotherObject.FirstOrDefault();
atheEntity.MyInteger = updInteger;
db.SubmitChanges(ConflictMode.ContinueOnConflict);
}
The above method deleted MyObject i got from the first query!!! Of course if i use the static context DataContext tries to update MyObject and MyAnotherObject which seems the correct behaviour.
Edit:
I have changed the method getting the integer with a new datacontext as well and seems to working correctly, i have a strange thought on why called the delete method, because it was the method that was called, but again .. is working now...
Thank you all for your time.
Yes it's possible. What have you tried? It should be as simple as this:
using (var dc = new YourDataContext())
{
Person p = dc.Persons.Take(1).Single();
p.FirstName = "Ahmad";
dc.SubmitChanges();
}
Yes, you can:
Foo foo = dc.Foos.Where(foo => foo.Id == 345).Single();
foo.Name = "foo";
dc.SubmitChanges();