你的问题
根据我的情况共享还是不共享 ObjectContext?不要分享您的背景。 EntityFramework 上下文应遵循 UnitOfWork 模式。您的对象上下文应该尽可能短,而不会不必要地创建/销毁太多上下文。这通常会转化为应用程序中作为工作单元的各个“操作”。对于网络应用程序/API,这可能是HttpWebRequest
,或者您可以针对每个逻辑数据操作执行此操作(对于每个已实现的“业务逻辑”部分)。
例如:
-
LoadBusinssObjects()
将创建一个上下文,加载您的数据列表以及您想要的任何相关数据,然后处理该上下文。
-
CreateBusinessObject()
将创建一个上下文,创建某个实体的实例,用数据填充它,将其附加到上下文中的收集,保存更改,然后处理上下文。
-
UpdateBusinessObject()
将从上下文中读取一些对象,更新它,保存更改并处理上下文。
-
DeleteBusinessObject()
将在上下文中找到业务对象,将其从上下文中的集合中删除,保存更改并处置上下文。
如果不分享,我如何解决目前用其他对象上下文中所做的更改更新一个对象上下文的问题?这是一份工作发布/订阅架构 http://msdn.microsoft.com/en-us/library/ff649664.aspx。这可以很简单,只需在对象上为上面实现的每个操作添加一些静态事件处理程序即可。然后,在每个业务操作的代码中,触发相应的事件。
如果分享 - 哪个会更好?静态还是单例还是其他什么?这是不正确的。随着上下文的状态管理器不断收集缓存的对象(附加的和未附加的),EF 上下文的内存占用将继续增长。每一次互动你在你的应用程序中所做的。上下文并不是为了这样工作而设计的。
除了资源使用之外,EF 上下文也不是线程安全的。例如,如果您希望允许编辑器表单之一在树列表加载一些新数据的同时保存一些更改,该怎么办?对于一个静态实例,您最好确保这一切都在 UI 线程上运行或与信号量同步(恶心,恶心 - 不好的做法)。
Example
这是一个根据您的帖子使用 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 - Microsoft 技术堆栈的 Comet 实现 http://www.frozenmountain.com/websync/。 WebSync 具有内置的所有功能,可将您想要订阅或发布的每个实体/事件的事件分离到逻辑“通道”中。是的,我在开发 WebSync 的软件公司工作 - 他们为我撰写本文时的时间付费。 :-)
但是,如果您不想为商业实现付费,您可以编写自己的 TCP 套接字客户端/服务器,以便在实体更改时分发上述事件的通知。然后,当订阅应用程序通过网络获取通知时,它可以以相同的方式触发其本地事件处理程序,这将导致本地视图刷新。您无法使用架构不佳的数据上下文静态实例来执行此操作(您将只能运行一个应用程序实例)。通过早期的一些良好设置,您可以轻松地在以后添加分布式发布-订阅系统,该系统可以同时跨本机应用程序和 Web 应用程序的多个实例运行!这变得非常强大。