乐观并发异常未被抛出:可能原因:UpdateCommand。

3
我只是想用EF 4.0实现一些数据库操作。我试图强制引发OptimisticConcurrencyException异常,但好像并不起作用。我认为如果在调用context.SaveChanges()之前数据库中的数据已经发生了改变,那么框架应该抛出OC异常,但它没有!我查看了更新命令,嘿 - 更新命令不包含我在edmx属性窗口中标记为并发模式FIXED的实体属性。为什么我的数据库表更改(将某些属性设置为FIXED并发模式)没有反映在我的更新命令中?这里是我已经在其他地方发布过的所有内容,但我猜所有问题都是因为FIXED值没有反映在我的更新命令中?有人有线索吗?
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的说明:

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>

这是 MSL:

<EntitySetMapping Name="Histories" StoreEntitySet="History" TypeName="MyModel.History">
  <ScalarProperty Name="HistoryId" ColumnName="HistoryId" />
  <ScalarProperty Name="HistoryKey" ColumnName="HistoryKey" />
  <ScalarProperty Name="HistoryText" ColumnName="HistoryText" />
  <ScalarProperty Name="RowVersion" ColumnName="RowVersion" />
</EntitySetMapping>

而且这个csdl:
<EntityType Name="History">
    <Key>
      <PropertyRef Name="HistoryId" />
    </Key>
    <Property Name="HistoryId" Type="Int64" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
    <Property Name="HistoryKey" Type="String" Nullable="false" MaxLength="100" Unicode="false" FixedLength="false" />
    <Property Name="HistoryText" Type="String" MaxLength="Max" Unicode="true" FixedLength="false" />
    <Property Name="RowVersion" Type="Binary" Nullable="false" MaxLength="8" FixedLength="true" annotation:StoreGeneratedPattern="Computed" />
  </EntityType>

POCO“历史”是在VS2010中使用修改过的ADO.NET POCO实体生成器生成的。

这是源代码:

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);
    }
  }
}

我该怎么做?

我有一个通过EF获取记录的进程A。

我有一个通过EF获取相同记录的进程B。

在进程A中更改此实体的属性值,并运行直到context.SaveChanges()方法(在调试器中设置断点)。

在进程B中更改相同属性的值并调用context.SaveChanges()。我也可以直接在数据库中进行更改。

糟糕的是,当我在进程A中步过context.SaveChanges()方法时,没有OC异常被抛出,正如我所期望的那样,因为数据库中的RowVersion属性存在,并且在edmx中标记为固定的。

属性更改已保存在数据库中。

然后我想到了一个主意——但这似乎不是完全合理的:如果它不起作用,为什么要将属性固定呢?

我想我知道为什么不会抛出异常。

这是因为固定属性的值没有更新,EF将比较原始值和修改后的值,对于这个固定属性...值是相同的——>不会抛出异常。从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 ===============

但是我的固定属性也应该包括在内吗?为什么它们不在更新语句中呢?
应该像这样:
=============== 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 ==============

有人能给我一些建议吗?谢谢!

1个回答

1

嗨,我找到了我的问题的答案:

我在一个单独的目录(d:\webservices)中使用cdsl、msdl和ssdl这三个文件,这不是我的汇编输出目录。 我使用EDMGEN.exe生成这三个文件。 关键是,用EDMGEN.EXE生成的csdl文件与.edmx文件的xml表示中的csdl内容部分不同,而来自edmgen.exe的csdl文件不包含CONCURRENCYMODE=FIXED属性,而.edmx文件中的csdl内容则包含此属性。 我不知道如何从我的edmx文件中生成这3个文件(metadataoutput设置为“copytooutputdirectory”——但输出目录只包含edmx文件,但我想要这3个文件都在那里:-(),但当我手动修改EDMGEN.EXE在d:\webservices中的csdl文件时,并发异常行为就正常工作了!

如果有人能提出如何重新创建这三个文件而无需使用EDMXGEN.exe的建议...我会非常感激:-)


现在我自己提取csdl、ssdl和msl。 - HarryK

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接