您的问题
针对我的情况分享还是不分享 ObjectContext?
不要分享你的上下文。 EntityFramework 上下文应该遵循 UnitOfWork 模式。您的对象上下文应尽可能短,而无需不必要地创建/销毁太多上下文。这通常会转化为应用程序中的单个“操作”作为工作单元。对于 Web 应用程序/api,这可能是每个 HttpWebRequest,或者您可以按逻辑数据操作(对于您实施的每个“业务逻辑”部分)进行。
例如:
-
LoadBusinssObjects() 将创建一个上下文,加载您的数据列表以及您想要的任何相关数据,然后处理该上下文。
-
CreateBusinessObject() 将创建一个上下文,创建某个实体的实例,用数据填充它,将其附加到上下文中的集合,保存更改,然后释放上下文。
-
UpdateBusinessObject() 会从上下文中读取一些对象,更新它,保存更改,然后释放上下文。
-
DeleteBusinessObject() 会在上下文中找到一个业务对象,将其从上下文的集合中移除,保存更改并释放上下文。
如果不分享,我该如何解决我目前的问题,即用另一个 objectContext 所做的更改来更新一个 objectContext?
这是pub/sub architecture 的工作。对于您在上面实现的每个操作,这可以像在对象上的几个静态事件处理程序一样简单。然后在每个业务操作的代码中,触发相应的事件。
如果要分享 - 哪种方式更好?静态或单例或其他?
这是不正确的。 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 组件都可以订阅对其重要的事件。如果您有一个树列表,然后是一些编辑器表单,则树列表将订阅任何更改以添加/更新/删除节点(或简单的方法 - 只需刷新整个树列表)。
应用程序之间的更新
如果您想更进一步,甚至在连接的环境中链接应用程序的单独实例,您可以使用WebSync - a comet implementation for the Microsoft Technology Stack 之类的东西通过网络实现发布/订阅事件系统。 WebSync 具有内置的所有内容,可以将事件分成逻辑“通道”,用于您要订阅或发布的每个实体/事件。是的,我为制作 WebSync 的软件公司工作——他们正在为我写这篇文章的时间付费。 :-)
但是,如果您不想为商业实现付费,您可以编写自己的 TCP 套接字客户端/服务器,在实体更改时为上述事件分发通知。然后,当订阅应用程序通过网络收到通知时,它可以触发其本地事件处理程序,其方式与刷新本地视图的方式相同。您不能使用架构不佳的数据上下文静态实例来执行此操作(您将只能运行一个应用程序实例)。通过早期的一些良好设置,您可以在以后轻松添加分布式发布-订阅系统,该系统可以同时跨多个本地应用程序和 Web 应用程序实例运行!这变得非常强大。