简体   繁体   English

不抛出OptimisticConcurrencyException:可能的原因:UpdateCommand

[英]OptimisticConcurrencyException is not thrown: Possible reason: UpdateCommand

I am just trying to realize some database stuff with EF 4.0. 我只是想用EF 4.0来实现一些数据库的东西。 I try to force a OptimisticConcurrencyException, but it does not seem to work. 我尝试强制使用OptimisticConcurrencyException,但它似乎不起作用。 I assume that if the data on the database have changed immediately before I make call to context.SaveChanges(), the framework should throw an OC exception - but it does not! 我假设如果在调用context.SaveChanges()之前数据库上的数据已经发生了变化,那么框架应该抛出一个OC异常 - 但事实并非如此! I had a look in update-command and voilà - the update command does not contain the properties from the entities which I have marked with concurrencyMode FIXED in the edmx properties window for that property. 我查看了update-command和voilà - update命令不包含我在该属性的edmx属性窗口中使用concurrencyMode FIXED标记的实体的属性。

Why are the changes in my database table (set some properties as FIXED for concurrency mode) not reflected in my updatecommand? 为什么我的数据库表中的更改(将并发模式的某些属性设置为FIXED)没有反映在我的updatecommand中?

Here is everything I have already posted somewhere, but I guess all the problems come up because of the FIXED values which are not reflected in my update command? 这是我已经在某处发布的所有内容,但我猜所有问题都出现了,因为我的更新命令中没有反映出FIXED值?

Anybody got a clue? 有人知道吗?

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

The ssdl states this: 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>

the msl this: 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>

and the csdl this: 和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 "history" was generated with a modified ADO.NET POCO Entity Generator in VS2010 POCO“历史”是使用VS2010中经过修改的ADO.NET POCO实体生成器生成的

This is the source: 这是来源:

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

What do I do? 我该怎么办?

I have a process A that gets a record via EF 我有一个进程A通过EF获取记录

I have a process B that gets the same record via EF 我有一个进程B通过EF获得相同的记录

Change the value of a property of this entity in process A and run until the context.SaveChanges() method (breakpoint in debugger) 在进程A中更改此实体的属性值,并运行到context.SaveChanges()方法(调试器中的断点)

Change the value of the same property in process B and call context.SaveChanges(). 更改进程B中相同属性的值并调用context.SaveChanges()。 I could also do this directly in the database. 我也可以直接在数据库中执行此操作。

The bad thing is, that when I step over the context.SaveChanges() method in process A, no OC-exception is thrown, as I would expect, as the RowVersion property in the database is present and it is marked as fixed in the edmx. 不好的是,当我跨过进程A中的context.SaveChanges()方法时,没有抛出OC异常,正如我所期望的那样,因为数据库中的RowVersion属性存在并且它被标记为固定在EDMX。

The propertychanges are saved in the database. 属性更改保存在数据库中。

THEN I THOUGHT I GOT AN IDEA - BUT THIS SEEMS TO BE NOT FULLY LOGICAL: WHY SHOULD I HAVE THE PROPERTY FIXED IF IT DOES NOT WORK? 那么我认为我得到了一个想法 - 但这个看起来并不完全逻辑:为什么我的财产如果不起作用就固定了?

I think I guess why the exception is not thrown. 我想我猜为什么不抛出异常。

This is because the value of the fixed property is not updatd and EF will compare the originalvalue and the modifiedvalue for this fixed property...and the values are the same --> no excpetion will be thrown. 这是因为固定属性的值不是更新的,EF将比较此固定属性的originalvalue和modifiedvalue ...并且值相同 - >不会抛出excpetion。 Seems to be correct from the EF side, but how can I get an exception thrown without requerying the value from the database and compare manually? 从EF方面来看似乎是正确的,但是如何在不重新获取数据库中的值并手动比较的情况下抛出异常? How can I get EF to check the value of the fixed property against the value in the database (and this value has in fact changed, because I did it manually in process B (resp. in the database))? 如何让EF检查固定属性的值与数据库中的值(实际上这个值已经改变了,因为我在进程B中手动完成(在数据库中相应))?

THE UPDATE-STATEMENT with the missing fixed properties: 缺少固定属性的更新声明:

=============== 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 ===============

But should include also my fixed properties? 但是还应该包括我的固定属性吗? Why are they not within the update statement? 为什么它们不在更新声明中?

SHOULD LOOK SOMETHING LIKE THAT I ASSUME: 应该看看我认为的一些东西:

=============== 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 ==============

Has somebody got any idea for me? 有人对我有任何想法吗? Thanks! 谢谢!

Hi, found the answer to my problems: 嗨,找到了我的问题的答案:

I use cdsl, msdl and ssdl in a separate directory (d:\\webservices, which is not my assembly output directory). 我在一个单独的目录中使用cdsl,msdl和ssdl(d:\\ webservices,这不是我的程序集输出目录)。 These three files I genereate with EDMGEN.exe. 这三个文件我用EDMGEN.exe生成。 The clue is, that the csdl file generated with the EDMGEN.EXE is different to the csdl-content-section in the xml-representation of the .edmx file and the csdl file from the edmgen.exe does not contain the CONCURRENCYMODE=FIXED attribute, whereas the csdl content in the .edmx-file does. 线索是,使用EDMGEN.EXE生成的csdl文件与.edmx文件的xml表示形式中的csdl-content-section不同,而edmgen.exe中的csdl文件不包含CONCURRENCYMODE = FIXED属性,而.edmx文件中的csdl内容确实如此。 I do not know how I can generate the 3 files from my edmx-file (metadataoutput is set to "copytooutputdirectory" - but output directory only contains the edmx-file, but I want the three files to be there :-( ), but when I manually modify the csdl file form the edmgen.exe in d:\\webservices, concurrency exception behavior works fine! 我不知道如何从我的edmx文件生成3个文件(metadataoutput设置为“copytooutputdirectory” - 但输出目录只包含edmx文件,但我希望这三个文件在那里:-(),但是当我手动修改d:\\ webservices中的edmgen.exe的csdl文件时,并发异常行为正常工作!

If somebody can propose how the get the three files recreated without edmxgen.exe...I would really appreciate this :-) 如果有人可以提出如何在没有edmxgen.exe的情况下重新创建三个文件......我真的很感激:-)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM