I saw something weird, from the point that was not what I was expecting.
Let’s take this simple code to allow you to see what I did:
MyRepository db = new MyRepository();
// let's get them all
IQueryable<TblCals> cals = db.FindAllCalendars();
// now that we have everything, let's split up
List<TblCals> masters = cals.Where(x => x.IsMaster).ToList();
List<TblCals> childs = cals.Where(x => x.Parent > 0).ToList();
// Let's change the name of the masters
foreach(var c in masters) c.Name = String.Concat("Master: ", c.Name);
// Let's send everything to the View
return View(new model() { masters, childs });
Now, the problem:
Why does the name changing in the List masters does also change the name of the objects that are in the childs?
When I do List<TblCals> masters = cals.Where(x => x.IsMaster).ToList(); shouldn’t this copy the elements instead of only referencing them from the cals object?
What can I do to prevent this behavior?
I could simple do:
MyRepository db = new MyRepository();
// let's get them all
IQueryable<TblCals> cals = db.FindAllCalendars();
// now that we have everything, let's split up
List<TblCals> masters = db.FindAllCalendarsThatAreMasters().ToList();
List<TblCals> childs = db.FindAllCalendarsThatHaveParent().ToList();
but this will end up being 3 queries to the database, and I could simply get all first and then use that object… but not if the “master” object keeps changing when I change any sub query from it.
The major idea behind all this, is to see if it is safe to do:
public IEnumerable<JK_Users> ListAllUsers() {
// Check / Add to memcache
string key = "ListAllUsers";
var users = MemcachedLayer.Get<IEnumerable<JK_Users>>(key);
if(key == null)
users = db.Tbl_Users.CachedQuery(key);
return users;
}
public IEnumerable<JK_Users> FindUserById(decimal id) {
// call ListAllUsers() instead Repository
return this.ListAllUsers().FirstOrDefault(x => x.user_id == id);
}
public IEnumerable<JK_Users> FindUserByUsername(string username) {
// call ListAllUsers() instead Repository
return this.ListAllUsers().FirstOrDefault(x => x.username == username);
}
or I do have to call
public JK_Users FindUserById(decimal id) {
return db.Tbl_Users.FirstOrDefault(x => x.user_id == id);
}
public JK_Users FindUserByUsername(string username) {
return db.Tbl_Users.FirstOrDefault(x => x.username == username);
}
So I can use the Cache more efficiently.
No, collections only ever contain references for reference types. There’s nothing EF-specific here:
The entity framework is ensuring that for any one “entity”, there’s only a single object (within the context of your repository object). That means you can’t get into the state where you’ve changed the same field on two different objects representing the same entity (where entity is defined by its ID).
This really is the logical approach – think of the values involved as entities; your two queries match the same entities for some results… why would you want those two results for the same entity to be independent objects? If someone refers to “Jon Skeet of Stack Overflow” and “Jon Skeet of Tilehurst, Reading, UK” that’s the same person – changing (say) the age via one result should change the age when seen via the other result.