C# 未引发OptimisticConcurrencyException:可能原因:UpdateCommand
我只是想用EF4.0实现一些数据库功能。 我试图强迫一个乐观的例外,但它似乎不起作用。 我假设,如果数据库中的数据在我调用context.SaveChanges()之前立即发生了更改,那么框架应该抛出一个OC异常——但它没有!我看了一下update命令,瞧——update命令不包含实体中的属性,我在edmx属性窗口中为该属性标记了concurrencyMode FIXED 为什么数据库表中的更改(将某些属性设置为并发模式的固定属性)没有反映在我的updatecommand中 这里是我已经发布的所有内容,但是我想所有的问题都是因为更新命令中没有反映的固定值而出现的 有人有线索吗C# 未引发OptimisticConcurrencyException:可能原因:UpdateCommand,c#,.net,sql-server,visual-studio-2010,entity-framework-4,C#,.net,Sql Server,Visual Studio 2010,Entity Framework 4,我只是想用EF4.0实现一些数据库功能。 我试图强迫一个乐观的例外,但它似乎不起作用。 我假设,如果数据库中的数据在我调用context.SaveChanges()之前立即发生了更改,那么框架应该抛出一个OC异常——但它没有!我看了一下update命令,瞧——update命令不包含实体中的属性,我在edmx属性窗口中为该属性标记了concurrencyMode FIXED 为什么数据库表中的更改(将某些属性设置为并发模式的固定属性)没有反映在我的updatecommand中 这里是我已经发布的所
USE [MyProject]
GO
/****** Object: Table [dbo].[History] Script Date: 02/19/2011 20:14:49 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[History](
[HistoryId] [bigint] IDENTITY(1,1) NOT NULL,
[HistoryKey] [varchar](100) NOT NULL,
[HistoryText] [varchar](max) NULL,
[RowVersion] [timestamp] NOT NULL,
CONSTRAINT [PK_History] PRIMARY KEY CLUSTERED
(
[HistoryId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ssdl规定:
<EntityType Name="History">
<Key>
<PropertyRef Name="HistoryId" />
</Key>
<Property Name="HistoryId" Type="bigint" Nullable="false" StoreGeneratedPattern="Identity" />
<Property Name="HistoryKey" Type="varchar" Nullable="false" MaxLength="100" />
<Property Name="HistoryText" Type="xml" />
<Property Name="RowVersion" Type="timestamp" Nullable="false" StoreGeneratedPattern="Computed" />
</EntityType>
我该怎么办
我有一个通过EF获取记录的流程a
我有一个进程B,它通过EF获得相同的记录
在进程a中更改此实体的属性值,并一直运行到context.SaveChanges()方法(调试器中的断点)
更改进程B中相同属性的值并调用context.SaveChanges()。我也可以直接在数据库中这样做
糟糕的是,当我跨过进程A中的context.SaveChanges()方法时,正如我所预料的那样,不会引发OC异常,因为数据库中存在RowVersion属性,并且它在edmx中被标记为已修复
属性更改保存在数据库中
然后我想我有了一个想法——但这似乎不完全符合逻辑:如果这个属性不起作用,为什么我要修复它
我想我猜为什么不抛出异常
这是因为固定属性的值未更新,EF将比较此固定属性的originalvalue和modifiedvalue…且值相同-->不会抛出expetion。从EF的角度来看似乎是正确的,但是如何在不重新查询数据库中的值并手动比较的情况下获得抛出的异常呢?我如何让EF根据数据库中的值检查固定属性的值(这个值实际上已经更改了,因为我是在进程B(分别在数据库中)中手动执行的)
UPDATE语句缺少固定属性:
=============== BEGIN COMMAND ===============
update [dbo].[History]
set [HistoryText] = @0
where ([HistoryId] = @1)
select [RowVersion]
from [dbo].[History]
where @@ROWCOUNT > 0 and [HistoryId] = @1
@0 = harald
@1 = 1
=============== END COMMAND ===============
但还应该包括我的固定资产吗?为什么它们不在update语句中
应该是这样的,我想:
=============== BEGIN COMMAND ===============
update [dbo].[History]
set [HistoryText] = @0
where ([HistoryId = @1) **AND ([ROWVERSION] = @2))**
select [RowVersion]
from [dbo].[History]
where @@ROWCOUNT > 0 and [HistoryId] = @1
@0 = harald
@1 = 1
**@2 = 0x000000045ef21**
=============== END COMMAND ==============
有人对我有什么想法吗?
谢谢 嗨,找到了我问题的答案:
我在一个单独的目录(d:\webservices,它不是我的程序集输出目录)中使用cdsl、msdl和ssdl。
这三个文件是我用EDMGEN.exe生成的。
线索是,使用EDMGEN.EXE生成的csdl文件与.edmx文件xml表示形式中的csdl内容部分不同,EDMGEN.EXE中的csdl文件不包含ConcurrentyMode=FIXED属性,而.edmx文件中的csdl内容包含ConcurrentyMode=FIXED属性。
我不知道如何从我的edmx文件生成3个文件(metadataoutput设置为“copytooutputdirectory”-但输出目录仅包含edmx文件,但我希望这三个文件存在:-(),但当我在d:\webservices中手动修改csdl文件形式的edmgen.exe时,并发异常行为工作正常
如果有人能建议如何在没有edmxgen.exe的情况下重新创建三个文件…我将非常感激:-)现在我自己提取csdl、ssdl和msl。
class Program
{
static void Main(string[] args)
{
using (var context = new MyEntities())
{
do
{
var query20 = (from p in context.Histories select p).OrderBy(p => p.HistoryId);
((ObjectQuery) query20).MergeOption = MergeOption.OverwriteChanges;
var query2 = query20.ToList();
History history = query2[0];
Console.WriteLine("found: " + history.HistoryKey + " ==> " + history.HistoryText + " ==> " +
Convert.ToBase64String(history.RowVersion));
var origRowVersion = history.RowVersion;
Console.WriteLine("Insert new key (q for exit):");
string newtext = Console.ReadLine();
if (newtext == "q")
break;
history.HistoryText = newtext;
try
{
context.DetectChanges();
var ose = context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified);
context.ObjectStateManager.ChangeObjectState(history, EntityState.Modified);
context.SaveChanges(SaveOptions.DetectChangesBeforeSave);
var newRowVersion = history.RowVersion;
if (newRowVersion == origRowVersion)
{
Console.WriteLine("rowversion unchanged");
}
else
{
Console.WriteLine("rowversion changed");
}
}
catch (OptimisticConcurrencyException)
{
Console.WriteLine("concurrencyexception occured!");
}
} while (true);
}
}
}
=============== BEGIN COMMAND ===============
update [dbo].[History]
set [HistoryText] = @0
where ([HistoryId] = @1)
select [RowVersion]
from [dbo].[History]
where @@ROWCOUNT > 0 and [HistoryId] = @1
@0 = harald
@1 = 1
=============== END COMMAND ===============
=============== BEGIN COMMAND ===============
update [dbo].[History]
set [HistoryText] = @0
where ([HistoryId = @1) **AND ([ROWVERSION] = @2))**
select [RowVersion]
from [dbo].[History]
where @@ROWCOUNT > 0 and [HistoryId] = @1
@0 = harald
@1 = 1
**@2 = 0x000000045ef21**
=============== END COMMAND ==============