EF6:SaveChanges覆盖,已更改的实体未在WPF中更新
我在EF6 DbContext中有一个覆盖的SaveChanges,在这里我设置了一些日期和用户。这些更改正在保存到数据库中,但我必须退出并重新打开WPF表单,然后才能在那里看到它们 SaveChanges覆盖是:EF6:SaveChanges覆盖,已更改的实体未在WPF中更新,wpf,entity-framework,Wpf,Entity Framework,我在EF6 DbContext中有一个覆盖的SaveChanges,在这里我设置了一些日期和用户。这些更改正在保存到数据库中,但我必须退出并重新打开WPF表单,然后才能在那里看到它们 SaveChanges覆盖是: //make sure we get all the changed objects ChangeTracker.DetectChanges(); ObjectContext ctx = ((IObjectContextAdapter) this).ObjectContext;
//make sure we get all the changed objects
ChangeTracker.DetectChanges();
ObjectContext ctx = ((IObjectContextAdapter) this).ObjectContext;
//get the current user name...
//TODO needs checking that this works when via service.
string userID = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
userID = userID.Substring(userID.IndexOf('\\') + 1); //remove domain
foreach (var dbEntityEntry in ctx.ObjectStateManager
.GetObjectStateEntries(EntityState.Added | EntityState.Modified)
.Where(e => e.Entity is IAuditInfo))
{
switch (dbEntityEntry.State)
{
case EntityState.Added:
((IAuditInfo) dbEntityEntry.Entity).CreatedOn = DateTime.Now;
((IAuditInfo) dbEntityEntry.Entity).CreatedBy = userID;
break;
case EntityState.Modified:
((IAuditInfo) dbEntityEntry.Entity).LastUpdatedOn = DateTime.Now;
((IAuditInfo) dbEntityEntry.Entity).LastUpdatedBy = userID;
break;
case EntityState.Deleted:
case EntityState.Detached:
case EntityState.Unchanged:
default:
break;
}
}
ctx.SaveChanges(SaveOptions.None);
return base.SaveChanges();
我的WPF XAML:
<Page.Resources>
<CollectionViewSource x:Key="actionStatusesViewSource"
d:DesignSource="{d:DesignInstance my:ActionStatus, CreateList=True}" />
</Page.Resources>
<Grid DataContext="{StaticResource actionStatusesViewSource}"
Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<DataGrid Grid.Row ="1"
AutoGenerateColumns="False"
EnableRowVirtualization="True"
ItemsSource="{Binding}"
Name="actionStatusesDataGrid"
RowDetailsVisibilityMode="VisibleWhenSelected"
VerticalAlignment="Top"
ClipboardCopyMode="IncludeHeader">
<DataGrid.Columns>
<DataGridTextColumn x:Name="idColumn"
Binding="{Binding Path=Id, Mode=TwoWay}"
Header="Id"
Width="SizeToHeader" />
<DataGridTextColumn x:Name="nameColumn"
Binding="{Binding Path=Name, Mode=TwoWay}"
Header="Name"
Width="256" />
<DataGridTemplateColumn x:Name="validFromColumn"
Header="Valid From"
Width="128">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding Path=ValidFrom, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn x:Name="validToColumn"
Header="Valid To"
Width="128">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding Path=ValidTo, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn x:Name="lastUpdatedByColumn"
Binding="{Binding Path=LastUpdatedBy, Mode=TwoWay}"
Header="Updated By"
Width="SizeToHeader" />
<DataGridTextColumn x:Name="lastUpdatedOnColumn"
Binding="{Binding Path=LastUpdatedOn, Mode=TwoWay, StringFormat=\{0:dd/MM/yyyy HH:mm\}}"
Header="Updated On"
Width="SizeToCells" />
<DataGridTextColumn x:Name="createdByColumn"
Binding="{Binding Path=CreatedBy, Mode=TwoWay}"
Header="Created By"
Width="SizeToHeader" />
<DataGridTextColumn x:Name="createdOnColumn"
Binding="{Binding Path=CreatedOn, Mode=TwoWay, StringFormat=\{0:dd/MM/yyyy HH:mm\}}"
Header="Created On"
Width="SizeToCells" />
</DataGrid.Columns>
</DataGrid>
最后是我的加载和保存代码:
private RegRiskContext context; //our model context (via the service)
private DataServiceCollection<ActionStatus> actionStatusBinding; //our bound collection
private CollectionViewSource viewSource; //the view source for the collection
private delegate void OperationResultCallback(); //delegate for the dispatcher invokes
public AdminActionStatus()
{
InitializeComponent();
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{
//get the CollectionViewSource object
viewSource = ((CollectionViewSource) (this.FindResource("actionStatusesViewSource")));
try
{
UIHelper.ProgressBarRun(true);
//initialise the context
context = new RegRiskContext(new Uri(RegRiskSettings.Default.ServiceURL));
//create a query ready for the async operation
DataServiceQuery<ActionStatus> dsq = context.ActionStatuses;
try
{
dsq.BeginExecute(OnQueryCompleted, dsq);
}
catch (DataServiceClientException ex)
{
MessageBox.Show(ex.ToString());
}
/* synchronous version
* note the freeze when opening the window
var q = context.ActionStatuses.OrderBy(f => f.Id);
DataServiceCollection<ActionStatus> actionStatuses = new DataServiceCollection<ActionStatus>(q);
viewSource.Source = actionStatuses;
*/
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void OnQueryCompleted(IAsyncResult result)
{
// Get the original query object from the state cache.
DataServiceQuery<ActionStatus> query = (DataServiceQuery<ActionStatus>) result.AsyncState;
//use Dispatcher to ensure we're on the UI thread!
this.Dispatcher.BeginInvoke(new OperationResultCallback(delegate
{
try
{
//instantiate the binding collection using results of the query
actionStatusBinding = new DataServiceCollection<ActionStatus>(query.EndExecute(result));
//set the Source to the collection
viewSource.Source = actionStatusBinding;
UIHelper.ProgressBarRun(false);
}
catch (DataServiceRequestException ex)
{
MessageBox.Show(ex.ToString());
}
}), null);
}
private void saveButton_Click(object sender, RoutedEventArgs e)
{
try
{
UIHelper.ProgressBarRun(true);
context.BeginSaveChanges(OnSaveChangesCompleted, null);
}
catch (DataServiceClientException ex)
{
MessageBox.Show(ex.ToString());
}
}
private void OnSaveChangesCompleted(IAsyncResult result)
{
// Use the Dispatcher to ensure that the operation returns in the UI thread.
this.Dispatcher.BeginInvoke(new OperationResultCallback(delegate
{
try
{
// Complete the save changes operation.
context.EndSaveChanges(result);
viewSource.View.Refresh();
UIHelper.ProgressBarRun(false);
}
catch (DataServiceRequestException ex)
{
MessageBox.Show(ex.ToString());
}
}), null);
}
privateReliskContext上下文//我们的模型上下文(通过服务)
私有DataServiceCollection actionStatusBinding//我们合订的藏品
私有集合viewSource viewSource//集合的视图源
私有委托无效操作ResultCallback()//分派器调用的委托
公共管理状态()
{
初始化组件();
}
已加载私有无效页面(对象发送方,路由目标e)
{
//获取CollectionViewSource对象
viewSource=((CollectionViewSource)(this.FindResource(“actionStatusesViewSource”));
尝试
{
UIHelper.ProgressBarRun(真);
//初始化上下文
context=new RegRiskContext(新Uri(RegRiskSettings.Default.ServiceURL));
//创建一个为异步操作准备好的查询
DataServiceQuery dsq=context.actionStatus;
尝试
{
dsq.BeginExecute(OnQueryCompleted,dsq);
}
捕获(DataServiceClientException ex)
{
Show(例如ToString());
}
/*同步版本
*注意打开车窗时的冻结
var q=context.ActionStatuses.OrderBy(f=>f.Id);
DataServiceCollection ActionStatus=新的DataServiceCollection(q);
viewSource.Source=操作状态;
*/
}
捕获(例外情况除外)
{
MessageBox.Show(例如Message);
}
}
私有void OnQueryCompleted(IAsyncResult结果)
{
//从状态缓存中获取原始查询对象。
DataServiceQuery=(DataServiceQuery)result.AsyncState;
//使用Dispatcher确保我们在UI线程上!
this.Dispatcher.BeginInvoke(新操作结果调用(委托
{
尝试
{
//使用查询结果实例化绑定集合
actionStatusBinding=newDataServiceCollection(query.EndExecute(result));
//将源设置为集合
viewSource.Source=actionStatusBinding;
UIHelper.ProgressBarRun(假);
}
捕获(DataServiceRequestException ex)
{
Show(例如ToString());
}
}),空);
}
私有无效保存按钮\u单击(对象发送方,路由目标)
{
尝试
{
UIHelper.ProgressBarRun(真);
context.BeginSaveChanges(OnSaveChangesCompleted,null);
}
捕获(DataServiceClientException ex)
{
Show(例如ToString());
}
}
保存更改上的私有无效已完成(IAsyncResult结果)
{
//使用Dispatcher确保操作在UI线程中返回。
this.Dispatcher.BeginInvoke(新操作结果调用(委托
{
尝试
{
//完成保存更改操作。
EndSaveChanges(结果);
viewSource.View.Refresh();
UIHelper.ProgressBarRun(假);
}
捕获(DataServiceRequestException ex)
{
Show(例如ToString());
}
}),空);
}
我不知道这是否是因为我的SaveChanges覆盖需要以某种方式通知?或者如果WPF是错误的?
WPF和EF之间有一个WCF DataServices层,但这看起来很“简单”,我甚至看不出我可以在那里做些什么更改。找到了一个解决方案,但不完全确定为什么要修复它,因此任何扩展的解释都将受到感激 我的WCF数据服务类很简单:
public class RegRiskService : EntityFrameworkDataService<BOI.RegRisk.Model.RegRiskContext>
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config)
{
// TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
//snip access stuff
}
}
公共类RegRiskService:EntityFrameworkDataService
{
//此方法只调用一次以初始化服务范围策略。
公共静态void InitializeService(DataServiceConfiguration配置)
{
//TODO:设置规则以指示哪些实体集和服务操作是可见的、可更新的等。
config.DataServiceBehavior.MaxProtocolVersion=DataServiceProtocolVersion.V3;
//剪断访问内容
}
}
这是协议版本,默认为v2,将其更改为v3似乎解决了问题。我的WPF datagrid现在使用SaveChanges覆盖中所做的更改进行更新
同样,对于任何有相同原始问题的人都有一个警告,我已经研究这个问题有一段时间了,所以有可能我改变了其他一些东西,这才是真正的根本原因