你的问题
为我的情况分享或不分享 ObjectContext?
不要分享你的上下文。EntityFramework 上下文应该遵循 UnitOfWork 模式。您的对象上下文应尽可能短,而无需不必要地创建/销毁太多上下文。这通常会转化为应用程序中的单个“操作”作为工作单元。对于 web 应用程序/api,这可能是 per HttpWebRequest
,或者您可以按逻辑数据操作(对于您实现的每个“业务逻辑”部分)执行此操作。
例如:
LoadBusinssObjects()
将创建一个上下文,加载您的数据列表以及您想要的任何相关数据,然后处理该上下文。
CreateBusinessObject()
将创建一个上下文,创建某个实体的实例,用数据填充它,将其附加到上下文中的集合,保存更改,然后处理上下文。
UpdateBusinessObject()
会从上下文中读取一些对象,更新它,保存更改,然后处理上下文。
DeleteBusinessObject()
将在上下文中找到一个业务对象,将其从上下文中的集合中删除,保存更改并处理上下文。
如果不分享,我该如何解决我目前使用另一个 objectContext 所做的更改来更新一个 objectContext 的问题?
这是pub/sub 架构的工作。对于您在上面实现的每个操作,这可以像在对象上的几个静态事件处理程序一样简单。然后在每个业务操作的代码中,触发相应的事件。
如果分享 - 哪个会更好?静态或单例或其他?
这是不正确的。EF 上下文的内存占用量将继续增长,因为上下文的状态管理器会为您在应用程序中执行的每一次交互不断收集缓存的对象(包括附加的和未附加的)。上下文不是这样设计的。
除了资源使用之外,EF 上下文也不是线程安全的。例如,如果您希望允许您的编辑器表单之一在树列表加载一些新数据的同时保存一些更改,该怎么办?使用一个静态实例,您最好确保这一切都在 UI 线程上运行或与信号量同步(呸,呸——不好的做法)。
例子
这是根据您的帖子使用 C# 和代码优先方法的示例。请注意,我没有解决诸如数据并发或线程之类的问题以保持示例简短。同样在实际应用程序中,这个概念是通过泛型和反射实现的,因此我们所有的模型都有用于创建、更新、删除的基本事件。
public class MyCodeFirstEntityChangedArgs : EventArgs
{
/// <summary>
/// The primary key of the entity being changed.
/// </summary>
public int Id {get;set;}
/// <summary>
/// You probably want to make this an ENUM for Added/Modified/Removed
/// </summary>
public string ChangeReason {get;set;}
}
public class MyCodeFirstEntity
{
public int Id {get;set;}
public string SomeProperty {get;set;}
/// <summary>
/// Occurs when an instance of this entity model has been changed.
/// </summary>
public static event EventHandler<MyCodeFirstEntityChangedArgs> EntityChanged;
}
public class MyBusinessLogic
{
public static void UpdateMyCodeFirstEntity(int entityId, MyCodeFirstEntity newEntityData)
{
using(var context = new MyEFContext())
{
// Find the existing record in the database
var existingRecord = context.MyCodeFirstEntityDbSet.Find(entityId);
// Copy over some changes (in real life we have a
// generic reflection based object copying method)
existingRecord.Name = newEntityData.Name;
// Save our changes via EF
context.SaveChanges();
// Fire our event handler so that other UI components
// subscribed to this event know to refresh/update their views.
// ----
// NOTE: If SaveChanges() threw an exception, you won't get here.
MyCodeFirstEntity.EntityChanged(null, new MyCodeFirstEntityChangedArgs()
{
Id = existingRecord.Id,
ChangeReason = "Updated"
});
}
}
}
现在您可以从任何地方(它是一个静态事件处理程序)将事件处理程序附加到您的模型,如下所示:
MyCodeFirstEntity.EntityChanged += new EventHandler<MyCodeFirstEntityChangedArgs>(MyCodeFirstEntity_LocalEventHandler);
然后在每个视图中都有一个处理程序,该处理程序将在触发此事件时刷新本地 UI 视图:
static void MyCodeFirstEntity_LocalEventHandler(object sender, MyCodeFirstEntityChangedArgs e)
{
// Something somewhere changed a record! I better refresh some local UI view.
}
现在,您拥有的每个 UI 组件都可以订阅对其重要的事件。如果您有一个树列表和一些编辑器表单,则树列表将订阅任何更改以添加/更新/删除节点(或简单的方法 - 只需刷新整个树列表)。
应用程序之间的更新
If you want to go a step further and even link separate instances of your app in a connected environment you can implement a pub/sub eventing system over the network using something like WebSync - a comet implementation for the Microsoft Technology Stack. WebSync has all the stuff built in to separate events into logical "channels" for each entity/event you want to subscribe to or publish to. And yes, I work for the software company who makes WebSync - they're paying for my time as I write this. :-)
But if you didn't want to pay for a commercial implementation, you could write your own TCP socket client/server that distributes notifications for the above events when an entity changes. Then when the subscribing app gets the notification over the network, it can fire its local event handlers the same way which will cause local views to refresh. You can't do this with a poorly architected static instance of your data context (you'd be bound to only ever have one instance of your app running). With some good setup early on, you can easily tack on a distributed pub-sub system later that works across multiple instances of native apps and web apps all at the same time! That gets very powerful.