检测单个实体是否需要保存在 EF4 和 WPF 中
我正在努力检测 EF4 中的实体是否有需要保存的更改。
离开 .NET 几年后,我肯定会用“生锈”这个词来形容我现在的处境。我正在尝试学习使用 EF4 和 WPF,同时重新熟悉 .NET。我已经学习了许多关于 Drag & 的教程。放弃使用实体框架和 WPF 进行数据绑定,并使用一些 Windows 构建一个应用程序,这让我的知识一点点增长。
我使用模型中最简单的部分进行训练练习,该模型具有实体:网络和实验室,网络和实验室之间存在多对多链接,即 NetworkLabs,这种关系现在并不是特别重要,因为我我仍然处于最基本的状态。
我有一个窗口,在列表框中显示网络列表,旁边有一个数据网格,显示网络中的实验室。我能够按照教程相当轻松地做到这一点,最终得到如下代码:
Public Class NetworkListWindow
Private Function GetNetworksQuery(entities As UKNEQASEntities) As ObjectQuery(Of Network)
Dim networksQuery As ObjectQuery(Of Network) = entities.Networks
' Update the query to include NetworkLabs data in Networks.
networksQuery = networksQuery.Include("NetworkLabs")
' Returns an ObjectQuery
Return networksQuery
End Function
Private Sub Window_Loaded(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
Dim entities As UKNEQASEntities = New UKNEQASEntities()
' Load data into Networks.
Dim networksViewSource As CollectionViewSource = CType(Me.FindResource("UKNEQASEntitiesNetworksViewSource"), CollectionViewSource)
Dim networksQuery As ObjectQuery(Of Network) = GetNetworksQuery(entities)
networksViewSource.Source = networksQuery.Execute(MergeOption.AppendOnly)
End Sub
End Class
该窗口仅供查看,用户可以单击编辑按钮来编辑所选网络。第二个窗口是我遇到问题的地方,在该窗口上,我将网络实体从“数据源”窗口拖到创建一个详细信息屏幕(行和列中带有标签和文本框的网格)。我最终得到了这样的代码:
Public Class NetworkWindow
Private m_id As Integer
Private m_db As New UKNEQASEntities
Public Sub New(id As Integer)
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
m_id = id
End Sub
Private Function GetNetworkQuery() As ObjectQuery(Of Network)
Dim networkQuery As ObjectQuery(Of Network) = m_db.Networks
' Update the query to include only the Network we are editing
networkQuery = networkQuery.Where(Function(net) net.Id = m_id)
' Update the query to include NetworkLabs data in Networks.
networkQuery = networkQuery.Include("NetworkLabs")
' Returns an ObjectQuery
Return networkQuery
End Function
Private Sub Window_Loaded(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
' Load data into Networks.
Dim networkViewSource As CollectionViewSource = CType(Me.FindResource("UKNEQASEntitiesNetworksViewSource"), CollectionViewSource)
Dim networksQuery As ObjectQuery(Of Network) = GetNetworkQuery()
networkViewSource.Source = networksQuery.Execute(MergeOption.AppendOnly)
' Get laboratories that are not in any networks
Dim labResult = From laboratory In m_db.Laboratories _
Where _
Not _
(From networklab In m_db.NetworkLabs _
Select networklab.Laboratory.Id).Contains(laboratory.Id) _
Select laboratory
Dim laboratoriesViewSource As CollectionViewSource = CType(Me.FindResource("UKNEQASEntitiesLaboratoriesViewSource"), CollectionViewSource)
laboratoriesViewSource.Source = labResult.ToList
End Sub
End Class
这对于显示在上一个屏幕上选择的网络效果很好,我在工具栏上放置了一个“保存”按钮,该按钮只需调用“
m_db.SaveChanges()
保存更改”并且效果也很好。我的问题出现在满足用户编辑数据并关闭窗口时,我想检测当前网络是否需要保存回数据库,以便我可以提示用户,但我不知道如何获取网络检查。
我怀疑这与以下代码有关:
Dim networkViewSource As CollectionViewSource = CType(Me.FindResource("UKNEQASEntitiesNetworksViewSource"), CollectionViewSource)
Dim entry As ObjectStateEntry = m_db.ObjectStateManager.GetObjectStateEntry(....)
但我不知道如何让网络传递给 GetObjectStateEntry。
在我之前的列表屏幕上,我可以通过从列表框中获取 SelectedItem 来获取所选网络,但我在单输入窗口中找不到任何可以帮助我的内容。
我以正确的方式处理这件事吗?对于单个条目编辑屏幕,我仍然使用 CollectionViewSource 就像我在列表屏幕上所做的那样,这是最好的方法还是有针对单个实体的东西?
我一直在寻找很多教程,我发现的大多数教程都是关于在 DataGrid 中显示数据进行编辑的,这不是我想要的。我正在努力寻找有关制作用于编辑单个实体的屏幕的任何帮助,因此不知道如何获取对用户正在编辑的实体的引用。
非常感谢任何帮助,因为我是这个 EF 和 XAML 的新手。
I am struggling with detecting whether an entity in EF4 has changes that need saving.
After a few years away from .NET rusty is definitely the word I'd use to describe where I am right now. I am trying to learn to use EF4 and WPF while reacquainting myself with .NET. I've followed a number of tutorials on Drag & Drop Databinding with the Entity Framework and WPF and built an app with a few Windows that is getting my knowledge up little by little.
I am using the simplest part of my Model for my training exercises, The model has entities: Network and Laboratory, there is a many-to-many link between Networks and Labs, namely NetworkLabs, the relationship is not particularly important right now as I am still at the very basics.
I have a window that displays a list of Networks in a listbox, with a DataGrid next to it showing the Laboratories in the Network. I was able to do that fairly easily following the tutorials and I ended up with code like:
Public Class NetworkListWindow
Private Function GetNetworksQuery(entities As UKNEQASEntities) As ObjectQuery(Of Network)
Dim networksQuery As ObjectQuery(Of Network) = entities.Networks
' Update the query to include NetworkLabs data in Networks.
networksQuery = networksQuery.Include("NetworkLabs")
' Returns an ObjectQuery
Return networksQuery
End Function
Private Sub Window_Loaded(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
Dim entities As UKNEQASEntities = New UKNEQASEntities()
' Load data into Networks.
Dim networksViewSource As CollectionViewSource = CType(Me.FindResource("UKNEQASEntitiesNetworksViewSource"), CollectionViewSource)
Dim networksQuery As ObjectQuery(Of Network) = GetNetworksQuery(entities)
networksViewSource.Source = networksQuery.Execute(MergeOption.AppendOnly)
End Sub
End Class
That window is for viewing only, the user can click an edit button to edit the selected network. That second window is where I am hitting problems, on that window I dragged the network entity over from the Data Sources window to create a details screen (a grid with labels and textboxes in the rows and columns). I ended up with code like:
Public Class NetworkWindow
Private m_id As Integer
Private m_db As New UKNEQASEntities
Public Sub New(id As Integer)
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
m_id = id
End Sub
Private Function GetNetworkQuery() As ObjectQuery(Of Network)
Dim networkQuery As ObjectQuery(Of Network) = m_db.Networks
' Update the query to include only the Network we are editing
networkQuery = networkQuery.Where(Function(net) net.Id = m_id)
' Update the query to include NetworkLabs data in Networks.
networkQuery = networkQuery.Include("NetworkLabs")
' Returns an ObjectQuery
Return networkQuery
End Function
Private Sub Window_Loaded(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
' Load data into Networks.
Dim networkViewSource As CollectionViewSource = CType(Me.FindResource("UKNEQASEntitiesNetworksViewSource"), CollectionViewSource)
Dim networksQuery As ObjectQuery(Of Network) = GetNetworkQuery()
networkViewSource.Source = networksQuery.Execute(MergeOption.AppendOnly)
' Get laboratories that are not in any networks
Dim labResult = From laboratory In m_db.Laboratories _
Where _
Not _
(From networklab In m_db.NetworkLabs _
Select networklab.Laboratory.Id).Contains(laboratory.Id) _
Select laboratory
Dim laboratoriesViewSource As CollectionViewSource = CType(Me.FindResource("UKNEQASEntitiesLaboratoriesViewSource"), CollectionViewSource)
laboratoriesViewSource.Source = labResult.ToList
End Sub
End Class
And that works fine for showing the network that was selected on the previous screen, I put a Save button on a toolbar which simply calls
m_db.SaveChanges()
To save the changes and that works fine as well. My problem comes when catering for when the user edits the data and closes the window, I want to detect whether the current network needs saving back to the database so I can prompt the user but I don't know how to get hold of the network to check.
I suspect it is something to do with code like:
Dim networkViewSource As CollectionViewSource = CType(Me.FindResource("UKNEQASEntitiesNetworksViewSource"), CollectionViewSource)
Dim entry As ObjectStateEntry = m_db.ObjectStateManager.GetObjectStateEntry(....)
but I don't know how to get the network to pass to GetObjectStateEntry.
On my previous list screen I was able to get the selected network by getting the SelectedItem from the listbox but I can't find anything that would help me on my single entry window.
Am I going about this the right way? For the single entry edit screen I am still using CollectionViewSource like I did for the list screen, is that the best way or is there something for single entities?
I have been looking for lots of tutorials and the majority I find are all about displaying the data for editing in DataGrids which is not what I am looking for. I am struggling to find any help on making screens for editing single entities so don't know how to pick up a reference to the entity the user is editing.
Any help is greatly appreciated as I am a novice at this EF and XAML lark.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
你从错误的角度看待它。开始使用 EF 时需要考虑的几件事:
你几乎不需要看
ObjectStateManager,这个东西
EF 应该可以帮到你。例如,如果您
想要关闭窗口并保存
一切,只需致电
context.SaveChanges() 并让 EF
找出需要的工作
节省什么。在某些情况下,您需要使用 ObjectStateManager,但这些情况是特定的,并且通常与非常自定义的事物相关联。
你没有看到很多例子,
因为正在构建 WPF 的人们
而 Silverlight 应用程序则不然
连接到数据库引擎,
相反,它们连接到一个或多个
Web 服务层并进行交互
和他们在一起。当您执行此操作时,
首先发生的事情是你不
使用“正常”EF 的工作时间更长
实体,这些不是被创造出来的
连载了。您将与以下任一方合作
POCO 自跟踪实体
实体。
如果您使用普通实体,
它们被设计为始终工作
附加到上下文(在你的情况下
它将是:UKNEQASentities),这个
意味着如果您尝试使用此
在客户端应用程序中你会想要
确保您始终使用相同的
上下文,所以要么有参考
在 Singleton 类上或注入它
它在依赖注入中
容器。如果您使用多个
你会遇到很多上下文
的相关问题
赋予对象的EntityKey
与它们存在的背景相关
在(将上下文视为记忆
您的数据库的副本,这不是
在实践中确实如此,它的工作原理更像是
您使用的界面
自动生成sql查询
您的数据库。
最后,如果你想构建一个好的 WPF 客户端应用程序,你还需要使用:
MEF(部署在
.Net 部署)或 Unity
(这是企业的一部分
图书馆)。
个人更喜欢这些而不是 POCO
对象,因为你得到了很多
强大的功能免费)。
如果您需要更具体的帮助,也可以直接戳我,我已经在大中型项目的专业开发团队中使用这些东西有一段时间了。然而我从来没有使用过Visual Basic,所以当我必须阅读VB代码时我有点痛苦!
You are looking at it from the wrong perspective. Several things that you need to consider when you start using EF:
You hardly need to look at
ObjectStateManager, this is something
EF is supposed to do for you. For example if you
want to close your Window and save
everything, just call
context.SaveChanges() and let EF to
the work of finding out what needs
saving and what not. There are cases where you need to use the ObjectStateManager, but these are specific and usually associated with very custom things.
You are not seeing many examples,
because people that are building WPF
and Silverlight applications aren't
connected to Data Base engines,
instead they connect to one or more
layers of Web Services and interact
with them. When you do this, the
first thing it happens is that you no
longer work with the "normal" EF
entities, these weren't made to be
serialized. You will work with either
POCO Entities of Self Tracking
Entities.
If you are using the normal Entities,
they are designed to allways work
attached to a context (in your case
it would be: UKNEQASEntities), this
means that if you attempt to use this
in a client application you will want
to make sure you allways use the same
context, so either have a reference
to it on a Singleton class or inject
it in a Dependency Injection
container. If you use multiple
contexts you will come across a bunch
of problems related with the
EntityKeys which are given to objects
in relation to the context they exist
in (consider the context a memory
copy of your Data Base, this isn't
true in practice, it works more like
an interface that you use to
auto-generate sql queries against
your Data Base.
In the end, if you want to build a good WPF client application you need to also use:
either MEF (which is deployed on
a .Net deployment) or Unity
(which is part of the Enterprise
Library).
personally perfer these over POCO
objects, because you get a lot of
powerfull functionality for free).
You can also poke me directly if you need more specific help, I've been working with this stuff for a while now, in professional development teams on medium to large scale projects. However I have never worked in Visual Basic, so I have a bit of pain when I have to read VB code!