I have an ASP.NET MVC (using the release candidate) application that works with a class library that among other things uses LINQ to SQL for data persistance.
我有一个ASP.NET MVC(使用候选版本)应用程序,它与类库一起工作,其中包括使用LINQ to SQL进行数据持久化。
One of the thing the app/db maintains, is the concept of a "Folder" - like a disk folder, but with a hierarchy that only exists in the database. Other database objects live in these folders, seen from the perspective of the user.
app / db维护的一件事是“文件夹”的概念 - 就像磁盘文件夹一样,但是层次结构只存在于数据库中。从用户的角度看,其他数据库对象位于这些文件夹中。
Each class in the class library has its own static reference to my DataContext object. In addition, the MVC controller each has it's own DataContext object.
类库中的每个类都有自己的DataContext对象的静态引用。另外,MVC控制器每个都有自己的DataContext对象。
I have two Actions returning JSON data. One is a "GetFoldersJSON" which returns the folder structure in a format suitable for a select (dropdown) list. The other one is "AddFolderJSON" which accepts some form data, inserts a new Folder into the database, and then returns GetFoldersJSON() for sending the new folder list to the client. The client uses AJAX with these actions to refresh the dropdownlists once a new folder is created.
我有两个Action返回JSON数据。一个是“GetFoldersJSON”,它以适合select(下拉列表)列表的格式返回文件夹结构。另一个是“AddFolderJSON”,它接受一些表单数据,将新文件夹插入数据库,然后返回GetFoldersJSON()以将新文件夹列表发送到客户端。创建新文件夹后,客户端将AJAX与这些操作一起使用以刷新下拉列表。
The flow of this operation is as such:
此操作的流程如下:
-
AddFolderJSON() action - Get the form information with new folder name, parent folder etc.
AddFolderJSON()操作 - 使用新文件夹名称,父文件夹等获取表单信息。
-
Create new Folder object. Perform a dataContext.Folders.InsertOnSubmit(newFolder); Perform a dataContext.SubmitChanges(); Perform a dataContext.Refresh(OverwriteThingy, dataContext.Folders); return result of GetFoldersJSON()
创建新的Folder对象。执行dataContext.Folders.InsertOnSubmit(newFolder);执行dataContext.SubmitChanges();执行dataContext.Refresh(OverwriteThingy,dataContext.Folders);返回GetFoldersJSON()的结果
-
GetFoldersJSON() uses a function which resides in the Folder definition - a partial class extending the OR-mapped folder object. This function recursively adds folders and subfolders to a flat list using code like this:
GetFoldersJSON()使用驻留在Folder定义中的函数 - 扩展OR映射文件夹对象的部分类。此函数使用以下代码以递归方式将文件夹和子文件夹添加到平面列表:
var rootFolders = from f in db.Folders where f.ParentFolder == null orderby f.name select f;
db is of course the local, static DataContext reference.
db当然是本地静态DataContext引用。
Then a simple loop:
然后一个简单的循环:
foreach (var fldr in rootFolders)
{
AddFolderContents(list, fldr);
}
The AddFolderContents() function then adds the current folder to the list, and proceeds to call itself for each subfolder of the current folder, thus creating a hierarchy.
AddFolderContents()函数然后将当前文件夹添加到列表中,并继续为当前文件夹的每个子文件夹调用自身,从而创建层次结构。
This works fine for data already in the database, but when we run this procedure after creating a new Folder, the new folder does not show up. If we refresh the page, it still doesn't show up. It doesn't actually show up until the application is restarted.
这适用于数据库中已存在的数据,但是当我们在创建新文件夹后运行此过程时,新文件夹不会显示。如果我们刷新页面,它仍然不会显示。在重新启动应用程序之前,它实际上不会显示。
I have tried to do Refresh() calls just about everywhere, and it seems to have no effect in this case.
我试图在任何地方进行Refresh()调用,在这种情况下似乎没有效果。
Is there a way to tell LINQ to SQL "Hey, I know what you're thinking, but DROP IT ALL, and just get ALL the data from the database, NOW!"?
有没有办法告诉LINQ to SQL“嘿,我知道你在想什么,但DROP IT ALL,现在只需从数据库中获取所有数据!”?
I have a nagging feeling I've heard about this before, but couldn't find it described here.
我之前听说过这种唠叨的感觉,但是在这里找不到它。
3 个解决方案
#1
Is there a way to tell LINQ to SQL "Hey, I know what you're thinking, but DROP IT ALL, and just get ALL the data from the database, NOW!"?
有没有办法告诉LINQ to SQL“嘿,我知道你在想什么,但DROP IT ALL,现在只需从数据库中获取所有数据!”?
db = new customDataContext();
db = new customDataContext();
db is of course the local, static DataContext reference
db当然是本地静态DataContext引用
Yeah, watch out there. ASP.NET is multithreaded and you don't want to share an unsafe-for-threading DataContext instance.
是的,请注意那里。 ASP.NET是多线程的,您不希望共享不安全的线程DataContext实例。
It seems as though you are accessing children folders through their parents. DataContext caches the state of objects it has already read and returns those same instances to you on further querying. The parent instance needs to be notified that it has a new child instance. Check out the generated ParentFolder property and see if it notifies the parent folder. If so, you're in business:
看起来好像是通过父母访问子文件夹。 DataContext缓存已读取的对象的状态,并在进一步查询时将相同的实例返回给您。需要通知父实例它具有新的子实例。检查生成的ParentFolder属性,看它是否通知父文件夹。如果是这样,你就是在做生意:
child.ParentFolder = parent;
If not, you need to do it this way:
如果没有,你需要这样做:
parent.Children.Add(child);
Do not do it by id, the autogenerated code does not notify the parent object in this case.
不要通过id来执行,在这种情况下,自动生成的代码不会通知父对象。
child.ParentFolderId = parent.Id; //bad, broken, do not do
Do this before your SubmitChanges call.
在SubmitChanges调用之前执行此操作。
#2
I have a feeling you aren't using the DataContext object (holding static references) in the way it's meant to be used.
我有一种感觉,你没有按照它的使用方式使用DataContext对象(持有静态引用)。
DataContext objects are meant to be used as a "unit of work"... Instantiate it, do your work, dispose of it. Need to do some more work? Instantiate another one, do your work, dispose of it.
DataContext对象旨在用作“工作单元”......实例化,完成工作,处理它。需要做更多的工作吗?实例化另一个,做你的工作,处理它。
In this MSDN page, Microsoft says:
在这个MSDN页面中,微软说:
The DataContext is the source of all entities mapped over a database connection. It tracks changes that you made to all retrieved entities and maintains an "identity cache" that guarantees that entities retrieved more than one time are represented by using the same object instance.
DataContext是通过数据库连接映射的所有实体的源。它跟踪您对所有检索到的实体所做的更改,并维护“身份缓存”,以确保通过使用相同的对象实例来表示检索多次的实体。
In general, a DataContext instance is designed to last for one "unit of work" however your application defines that term. A DataContext is lightweight and is not expensive to create. A typical LINQ to SQL application creates DataContext instances at method scope or as a member of short-lived classes that represent a logical set of related database operations.
通常,DataContext实例设计为持续一个“工作单元”,但是您的应用程序定义该术语。 DataContext是轻量级的,创建起来并不昂贵。典型的LINQ to SQL应用程序在方法范围内创建DataContext实例,或者作为表示相关数据库操作的逻辑集的短期类的成员。
Similarly, if you read the bottom of Joseph and Ben Albahari's 10 LINQ Myths page (they are the authors of C# In A Nutshell) you will see this quote about using a static datacontext:
同样,如果你阅读Joseph和Ben Albahari的10个LINQ Myths页面的底部(他们是C#In A Nutshell的作者),你会看到关于使用静态datacontext的这句话:
This strategy will result in stale data, because objects tracked by a DataContext instance are not refreshed simply by requerying.
此策略将导致过时数据,因为DataContext实例跟踪的对象不会仅通过重新查询来刷新。
Using a single static DataContext instance in the middle tier of a distributed application will cause further trouble, because DataContext instances are not thread-safe.
在分布式应用程序的中间层中使用单个静态DataContext实例将导致进一步的麻烦,因为DataContext实例不是线程安全的。
The correct approach is to instantiate fresh DataContext objects as required, keeping DataContext instances fairly short-lived.
正确的方法是根据需要实例化新的DataContext对象,使DataContext实例保持相当短暂。
#3
My first instinct was:-
我的第一直觉是: -
David B has given you one of the poissibilites, new up the DataContect but there is another.
大卫B给了你一个poissibilites,新的DataContect,但还有另一个。
db.Refresh(System.Data.Linq.RefreshMode.KeepChanges, myObjectsCollection)
myObjectionCollection is Collection of all the Linq objects that you want refreshed from the datatase. (i.e. mostly everthing in your case).
myObjectionCollection是要从数据集刷新的所有Linq对象的集合。 (即在你的情况下大多数情况下)。
Beware it's sllllooooowwwww! Apparently it's better in EF - see here.
小心它的sllllooooowwwww!显然它在EF中更好 - 见到这里。
However on more careful re-reading I'm not sure what it going on. Linq should find new records (but not updated records) and they should appear even without a refresh.
然而,在更仔细地重新阅读时,我不确定它是怎么回事。 Linq应该找到新的记录(但不是更新的记录),即使没有刷新它们也应该出现。
Hmmmm....
#1
Is there a way to tell LINQ to SQL "Hey, I know what you're thinking, but DROP IT ALL, and just get ALL the data from the database, NOW!"?
有没有办法告诉LINQ to SQL“嘿,我知道你在想什么,但DROP IT ALL,现在只需从数据库中获取所有数据!”?
db = new customDataContext();
db = new customDataContext();
db is of course the local, static DataContext reference
db当然是本地静态DataContext引用
Yeah, watch out there. ASP.NET is multithreaded and you don't want to share an unsafe-for-threading DataContext instance.
是的,请注意那里。 ASP.NET是多线程的,您不希望共享不安全的线程DataContext实例。
It seems as though you are accessing children folders through their parents. DataContext caches the state of objects it has already read and returns those same instances to you on further querying. The parent instance needs to be notified that it has a new child instance. Check out the generated ParentFolder property and see if it notifies the parent folder. If so, you're in business:
看起来好像是通过父母访问子文件夹。 DataContext缓存已读取的对象的状态,并在进一步查询时将相同的实例返回给您。需要通知父实例它具有新的子实例。检查生成的ParentFolder属性,看它是否通知父文件夹。如果是这样,你就是在做生意:
child.ParentFolder = parent;
If not, you need to do it this way:
如果没有,你需要这样做:
parent.Children.Add(child);
Do not do it by id, the autogenerated code does not notify the parent object in this case.
不要通过id来执行,在这种情况下,自动生成的代码不会通知父对象。
child.ParentFolderId = parent.Id; //bad, broken, do not do
Do this before your SubmitChanges call.
在SubmitChanges调用之前执行此操作。
#2
I have a feeling you aren't using the DataContext object (holding static references) in the way it's meant to be used.
我有一种感觉,你没有按照它的使用方式使用DataContext对象(持有静态引用)。
DataContext objects are meant to be used as a "unit of work"... Instantiate it, do your work, dispose of it. Need to do some more work? Instantiate another one, do your work, dispose of it.
DataContext对象旨在用作“工作单元”......实例化,完成工作,处理它。需要做更多的工作吗?实例化另一个,做你的工作,处理它。
In this MSDN page, Microsoft says:
在这个MSDN页面中,微软说:
The DataContext is the source of all entities mapped over a database connection. It tracks changes that you made to all retrieved entities and maintains an "identity cache" that guarantees that entities retrieved more than one time are represented by using the same object instance.
DataContext是通过数据库连接映射的所有实体的源。它跟踪您对所有检索到的实体所做的更改,并维护“身份缓存”,以确保通过使用相同的对象实例来表示检索多次的实体。
In general, a DataContext instance is designed to last for one "unit of work" however your application defines that term. A DataContext is lightweight and is not expensive to create. A typical LINQ to SQL application creates DataContext instances at method scope or as a member of short-lived classes that represent a logical set of related database operations.
通常,DataContext实例设计为持续一个“工作单元”,但是您的应用程序定义该术语。 DataContext是轻量级的,创建起来并不昂贵。典型的LINQ to SQL应用程序在方法范围内创建DataContext实例,或者作为表示相关数据库操作的逻辑集的短期类的成员。
Similarly, if you read the bottom of Joseph and Ben Albahari's 10 LINQ Myths page (they are the authors of C# In A Nutshell) you will see this quote about using a static datacontext:
同样,如果你阅读Joseph和Ben Albahari的10个LINQ Myths页面的底部(他们是C#In A Nutshell的作者),你会看到关于使用静态datacontext的这句话:
This strategy will result in stale data, because objects tracked by a DataContext instance are not refreshed simply by requerying.
此策略将导致过时数据,因为DataContext实例跟踪的对象不会仅通过重新查询来刷新。
Using a single static DataContext instance in the middle tier of a distributed application will cause further trouble, because DataContext instances are not thread-safe.
在分布式应用程序的中间层中使用单个静态DataContext实例将导致进一步的麻烦,因为DataContext实例不是线程安全的。
The correct approach is to instantiate fresh DataContext objects as required, keeping DataContext instances fairly short-lived.
正确的方法是根据需要实例化新的DataContext对象,使DataContext实例保持相当短暂。
#3
My first instinct was:-
我的第一直觉是: -
David B has given you one of the poissibilites, new up the DataContect but there is another.
大卫B给了你一个poissibilites,新的DataContect,但还有另一个。
db.Refresh(System.Data.Linq.RefreshMode.KeepChanges, myObjectsCollection)
myObjectionCollection is Collection of all the Linq objects that you want refreshed from the datatase. (i.e. mostly everthing in your case).
myObjectionCollection是要从数据集刷新的所有Linq对象的集合。 (即在你的情况下大多数情况下)。
Beware it's sllllooooowwwww! Apparently it's better in EF - see here.
小心它的sllllooooowwwww!显然它在EF中更好 - 见到这里。
However on more careful re-reading I'm not sure what it going on. Linq should find new records (but not updated records) and they should appear even without a refresh.
然而,在更仔细地重新阅读时,我不确定它是怎么回事。 Linq应该找到新的记录(但不是更新的记录),即使没有刷新它们也应该出现。
Hmmmm....