我看到一些奇怪的东西,从我不期望的那一点开始。
让我们用这个简单的代码让你看看我做了什么:
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 });
现在,问题:
为什么List
masters
中的名称更改也会更改childs
中的对象名称?
当我List<TblCals> masters = cals.Where(x => x.IsMaster).ToList();
时,不应该复制元素而不是仅从cals
对象引用它们吗?
我该怎么做以防止此行为?
我可以这么简单:
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();
但这将最终成为对数据库的3次查询,我可以先获取所有内容然后再使用该对象...但是当我更改时“master”对象不断变化来自它的任何子查询。
这一切背后的主要思想是看它是否安全:
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);
}
或者我必须致电
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);
}
所以我可以更有效地使用缓存。
答案 0 :(得分:3)
不,集合只包含引用类型的引用。这里没有特定于EF的内容:
List<StringBuilder> list1 = new List<StringBuilder>();
List<StringBuilder> list2 = new List<StringBuilder>();
StringBuilder builder = new StringBuilder();
list1.Add(builder);
list2.Add(builder);
list1[0].Append("Foo");
Console.WriteLine(list2[0]); // Still prints Foo...
实体框架确保对于任何一个“实体”,只有一个对象(在您的存储库对象的上下文中)。这意味着您无法进入您在代表同一实体的两个不同对象上更改相同字段的状态(实体由其ID定义)。
这确实是合乎逻辑的方法 - 想想作为实体所涉及的价值观;对于某些结果,您的两个查询匹配相同的实体...为什么您希望同一实体的这两个结果是独立对象?如果有人提到“Stack Overflow的Jon Skeet”和“Tilehurst,英国雷丁的Jon Skeet”,那就是同一个人 - 通过一个结果改变(比方说)年龄应该改变年龄另一个结果。