How to load multiple related entities in DbUpdateConcurrencyException - asp.net-mvc-3

I have 3 related tables
Person entity: with two Foreign keys from Address entity (Address and Address1) and one foreign key from Owners table
Address Entity has one foreign key from Owners table
The person view has fields from Address entity and while tracking the concurrency check
var entry = ex.Entries.Single();
var databaseValues = (Person)entry.GetDatabaseValues().ToObject();
var clientValues = (Person)entry.Entity;
works fine for Person fields.
However when I try to access
databasevalues.Address.City or databasevalues.Address1.City it gives a null exception. This I think is due to Address Entity not loaded in the begining
Request for suggestions

You might try explicitly loading the related entities in your query:
IQueryable<Person> persons = DataContext.Persons.Where(p => p.City == "Hoboken").Include("Address")
would explicitly load related address entries for the person instances returned.
Another option is to disable the Lazy Loading option in your edmx file; open the file, then the properties panel, set Lazy Loading = false.

Related

Entity Framework 4.1: Possible to save a single table out of a data context containing multiple tables?

I have a chicken and egg problem, it's trivial, so I thought I would ask what's the normal pattern to save an aggregate root where all the primary keys are identity fields.
I have a typical contact entity:
Customer {
HomeAddress {
}
WorkAddress {
}
}
where both addresses are stored in the address table and the only primary key is the identity field. We check all fields against each other to keep unique address records.
Here's the problem:
I need to retrieve the Address identity field to hookup the foreign keys, so I save the Address record prior to saving the Customer record only if it's unique, otherwise I load that existing Address.
If Address is in the same DC as Customer, then customer saves too prematurely (not all records are set.)
If Address is in a separate DC, then it doesn't hookup to the Customer record that has it's own DC because you cannot have an entity associated with two DCs (can't open in one, then save in another.)
So my thinking is that I would need a separate repository for every Address, then separately load the address again in the other DC, making redundant calls to the database for the same information.
Is there a way to partially save records in a data context / container in Entity Framework 4.1? For example, to save Address by itself while still being in the same DC?
The answer to your bold question is "No" as far as I can tell. The context is a unit of work and SaveChanges commits every new, changed or deleted object to the database in a single transaction. You cannot selectively say: Save only this or that object or save only entities in state Added and don't commit entities in state Modified or Deleted or something.
As a workaround you could try that:
using (var context1 = new MyContext())
{
Address address = context1.Addresses.Where(predicate).FirstOrDefault();
// if address != null it is attached now to context1
if (address == null)
{
// ... otherwise create new address in another context and save
using (var context2 = new MyContext())
{
address = new Address { Name = name, ... }
context2.Addresses.Add(address);
context2.SaveChanges();
} // context2 destroyed now and address is not attached to it anymore
// ... and attach to context1
context1.Addresses.Attach(address);
}
customer.HomeAddress = address;
// ...
context1.SaveChanges();
}
This way address is never attached to the two contexts at the same time. I am not sure though if this works.
Edit
I must add (because my code above looks so weird) that "normally" you could do all this in context1 alone. But I understood your point 2 this way that there is something happening in // ... (which I don't understand) before SaveChanges which prevents you to save the new address and the customer at the same time.

linq with Include and criteria

How would I translate this into LINQ?
Say I have A parent table (Say, customers), and child (addresses).
I want to return all of the Parents who have addresses in California, and just the california address. (but I want to do it in LINQ and get an object graph of Entity objects)
Here's the old fashioned way:
SELECT c.blah, a.blah
FROM Customer c
INNER JOIN Address a on c.CustomerId = a.CustomerId
where a.State = 'CA'
The problem I'm having with LINQ is that i need an object graph of concrete Entity types (and it can't be lazy loaded.
Here's what I've tried so far:
Edit: added context instantiation as requested
// this one doesn't filter the addresses -- I get the right customers, but I get all of their addresses, and not just the CA address object.
var ctx = new CustomersContext() // dbContext -- using EF 4.1
from c in ctx.Customer.Include(c => c.Addresses)
where c.Addresses.Any(a => a.State == "CA")
select c
// this one seems to work, but the Addresses collection on Customers is always null
var ctx = new CustomersContext() // dbContext -- using EF 4.1
from c in ctx.Customer.Include(c => c.Addresses)
from a in c.Addresses
where a.State == "CA"
select c;
Any ideas?
Based on the code above, it appears that you already have a rehydrated collection of Customer objects in the Customer variable.
You will need to call the Include function when you fill your Customer collection above. This way, the framework will rehydrate the included objects at the time of retrieval from your data context.
The actual query code appears good though.

Table with a foreign key

how can I build a table of "orders" containing "IdOrder", "Description" and "User"?... the "User" field is a reference to the table "Users", which has "IdUser" and "Name". I'm using repositories.
I have this repository:
Repository<Orders> ordersRepo = new OrderRepo<Orders>(unitOfWork.Session);
to return all Orders to View, I just do:
return View(ordersRepo.All());
But this will result in something like:
IdOrder:1 -- Description: SomeTest -- User: UserProxy123ih12i3123ih12i3uh123
-
When the expected result was:
IdOrder:1 -- Description: SomeTest -- User: Thiago.
PS: I don't know why it returns this "UserProxy123ih12i3123ih12i3uh123". In Db there is a valid value.
The View:
It is showed in a foreach (var item in Model).
#item.Description
#item.User //--> If it is #item.User.Name doesn't work.
What I have to do to put the Name on this list? May I have to do a query using LINQ - NHibernate?
Tks.
What type of ORM are you using? You mention "repositories" but does that mean LinqToSql, Entity Framework, NHibernate, or other?
It looks like you are getting an error because the User field is not loaded as part of the original query. This is likely done to reduce the size of the result set by excluding the related fields from the original query for Orders.
There are a couple of options to work around this:
Set up the repository (or context, depending on the ORM) to include the User property in the result set.
Explicitly load the User property before you access it. Note that this would be an additional round-trip to the database and should not be done in a loop.
In cases where you know that you need the User information it would make sense to ensure that this data in returned from the original query. If you are using LinqToSql take a look at the DataLoadOptions type. You can use this type to specify which relationships you want to retrieve with the query:
var options = new DataLoadOptions();
options.LoadWith<Orders>(o => o.User);
DataContext context = ...;
context.LoadOptions = options;
var query = from o in context.Orders
select o;
There should be similar methods to achive the same thing whatever ORM you are using.
In NHibernate you can do the following:
using (ISession session = SessionFactory.OpenSession())
{
var orders = session.Get<Order>(someId);
NHibernateUtil.Initialize(orders.User);
}
This will result in only two database trips (regardless of the number of orders returned). More information on this can be found here.
In asp.net MVC the foreign key doesn't work the way you are using it. I believe you have to set the user to a variable like this:
User user = #item.User;
Or you have to load the reference sometimes. I don't know why this is but in my experience if I put this line before doing something with a foreign key it works
#item.UserReference.load();
Maybe when you access item.User.Name the session is already closed so NHib cannot load appropriate user from the DB.
You can create some model and initialize it with proper values at the controller. Also you can disable lazy loading for Orders.User in your mapping.
But maybe it is an other problem. What do you have when accessing "#item.User.Name" from your View?

How do I get like to return data from multiple tables?

I'm trying to modify the following query to return data from multiple tables.
I have the main contacts table where all contact details are stored. Companies are also stored in the Contacts table. Companies are mapped to Contacts in a join table named CompanyPersonMap.
I also have an attributes table where the contacts are assigned certain attributes, possibly many per contact.
Now, I want to return all the contacts that have a certain attribute assigned PLUS the person's Company name and address found in a different row in the Contacts table.
This code works but only returns the contactId. Fine for what I needed but I can't figure out how to modify it for the above requirement.
var peopleAndAddresses = Contacts.Where(c => c.AssignedAttributes
.Any (aa => aa.AttributeID == 1153))
.Select(x => x.ContactID);
Any suggestions for doing this?
Thanks!
Edit-
I tried working on the .Select() statement and found the path from the contact to its organzation via the PersonOrgMap table. Unfortunately, I can't get any of the data about the organization. I tried .Any(), .All(), and .FirstOrDefault(). Any suggestions?
.Select (c => new {c.FirstName, c.LastName, c.PersonOrgMap.FirstOrDefault (pom => pom.ChildContactID) })
This code below will get you all Contacts that have at least one AssignedAttribute with an AttributeID of 1153. I think this is what you're looking for.
var peopleAndAddress = Contacts
.Where(c => c.AssignedAttributes.Any(aa => aa.AttributeID == 1153))
.Select(c => c);
However, your statement "name and address found in a different row in the Contacts table" makes me think that this might not be what you need. Can you just get what the Company Name and Address is from properties on Contact?

LINQ not updating on .SubmitChanges()

Is there any reason something like this would not work?
This is the logic I have used many times to update a record in a table with LINQ:
DataClasses1DataContext db = new DataClasses1DataContext();
User updateUser = db.Users.Single(e => e.user == user);
updateUser.InUse = !updateUser.InUse;
db.Log = new System.IO.StreamWriter(#"c:\temp\linq.log") { AutoFlush = true };
db.SubmitChanges();
(updateUser.InUse is a bit field)
For some reason it isn't working. When I check the linq.log it is completely blank.
Could there be a problem with my .dbml? Other tables seem to work fine but I've compared properties in the .dbml and they all match.
It's as if the db.SubmitChanges(); does not detect any updates being required.
The table could not be updated properly because it had no primary key. (Actually it had the column but the constraint was not copied when I did a SELECT INTO my dev table). The DataContext class requires a primary key for updates.
Is the InUse property a "normal" one as far as LINQ is concerned? (e.g. it's not autogenerated or anything funky like that?)
Alternatively, I don't suppose it's a Nullable<bool> is it, with a current value of null? If so, your update line isn't actually doing anything - for nullable Booleans, !null = null.

Resources