none
How to automate setting ConcurrencyMode=Fixed on all RowVersion columns? RRS feed

  • Question

  • EF defaults to no concurrency control (last write wins) which allows lost updates.
    Enforcing optimistc concurrency checks can explicitely be configured by setting ConcurrencyMode=Fixed on a RowVersion column.

    How can we automate setting ConcurrencyMode=Fixed on all RowVersion columns?
    Having to do this manually when recreating an EF model from a database we risk forgetting it an running without concurrency control.
    Thursday, October 4, 2012 3:49 PM

Answers

All replies

  • Hi Pmeinl,

    Welcome to the MSDN forum.

    You can use some Optimistic Concurrency Patterns described here: http://blogs.msdn.com/b/adonet/archive/2011/02/03/using-dbcontext-in-ef-feature-ctp5-part-9-optimistic-concurrency-patterns.aspx

    Good day.


    Alexander Sun [MSFT]
    MSDN Community Support | Feedback to us

    Monday, October 8, 2012 1:00 PM
  • Hi Alexander,

    my question was not how to handle optimistic concurrency exceptions but how to configure the model automatically to ConcurrencyMode=Fixed on all RowVersion columns. Without this setting optimistic concurrency exceptions are not thrown.

    Because almost every DB application uses concurrency control I expect there to be a way to automatically make the setting and not have to manually set it for each table.

    Monday, October 8, 2012 1:37 PM
  • Hi Prmeinl,

    Sorry for late response.

    If you use Database first and Model first, the setting code is located in edmx file which is a xml file. As far as I know, you have to set concurrencymode manually or write a method to check and edit the edmx. You can submit a feature request here: http://data.uservoice.com/forums/72025-ado-net-entity-framework-ef-feature-suggestions

    Best Regards,


    Alexander Sun [MSFT]
    MSDN Community Support | Feedback to us


    Friday, October 12, 2012 8:04 AM
  • I do not understand why such a basic feature does not exist.
    Made a feature request at EF CodePlex Automate setting ConcurrencyMode=Fixed

    • Edited by pmeinl Sunday, October 14, 2012 12:26 PM
    • Marked as answer by pmeinl Sunday, October 14, 2012 12:26 PM
    Sunday, October 14, 2012 12:22 PM
  • I agree that this is a basic feature. I solved the problem by opening the .edmx file as xml and replacing all

    <Property Type="Binary" Name="RV" Nullable="false" MaxLength="8" FixedLength="true" annotation:StoreGeneratedPattern="Computed" />

    Whith

    <Property Type="Binary" Name="RV" Nullable="false" MaxLength="8" FixedLength="true" annotation:StoreGeneratedPattern="Computed" ConcurrencyMode="Fixed" />
    

    Tuesday, October 16, 2012 9:45 AM
  • Yes, that is how we do this too.

    But it has happened that we forgot to do this manually when recreating the model from the DB and this will happen again.

    I am looking for a way to do this automatically or by default.

    Tuesday, October 16, 2012 12:24 PM
  • I am looking into this too, but I am thinking the easiest way top do it would be to have all entities inherit from a single abstract base class that contains the PK and Row Version columns, then you only need to set it once and in one place.  This is what we do now in another ORM tool, works great in that system

    JAMES


    JPK


    • Edited by James Klett Thursday, December 27, 2012 4:22 PM
    Thursday, December 27, 2012 4:11 PM
  • I wrote a XSL-stylesheet to solve this problem for two of my projects. It interprets the EDMX (which is a XML file) and sets the ConcurrencyMode of all columns with the name 'Timestamp' to 'Fixed'

    Here it is:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:csdl="http://schemas.microsoft.com/ado/2008/09/edm">
    	<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    	<xsl:template match="@*|node()">
    		<xsl:copy>
    			<xsl:apply-templates select="@*|node()"/>
    		</xsl:copy>
    	</xsl:template>
    	<xsl:template match="csdl:Property[@Name='Timestamp']">
    		<xsl:copy>
    			<xsl:apply-templates select="@* | node()"/>
    			<xsl:attribute name="ConcurrencyMode">
    				<xsl:text>Fixed</xsl:text>
    			</xsl:attribute>
    		</xsl:copy>
    	</xsl:template>
    </xsl:stylesheet>
    Tuesday, January 8, 2013 7:13 PM
  • A newbie to EF so, Can you add instructions for how to use this? Where top copy it to etc...

    JPK


    ...
    • Edited by James Klett Monday, April 8, 2013 2:41 PM test
    Tuesday, January 8, 2013 10:44 PM
  • Seems like this Feature is not going to be around for EF 5 or EF 6.

    I whipped up a quick console app to update the edmx after generating DB First.

    Just drop the file in the same directory of your edmx file and run after every regeneration.

    Will work for any of the following columns:

    • RowVersion    timestamp    NOT NULL
    • rowversion     timestamp    NOT NULL
    • RowVer           timestamp    NOT NULL
    • rowver            timestamp    NOT NULL

    You can get the console app here https://dl.dropbox.com/u/3576345/EFConcurrencyFixed.exe

    or use this piece of code in your own console app.

    class Program
        {
            static Dictionary<string, string> replacements = new Dictionary<string, string>()
            {
                { "<Property Type=\"Binary\" Name=\"RowVersion\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" />",
                  "<Property Type=\"Binary\" Name=\"RowVersion\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" ConcurrencyMode=\"Fixed\" />"},
                
                { "<Property Type=\"Binary\" Name=\"rowversion\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" />",
                  "<Property Type=\"Binary\" Name=\"rowversion\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" ConcurrencyMode=\"Fixed\" />"},
                
                { "<Property Type=\"Binary\" Name=\"RowVer\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" />",
                  "<Property Type=\"Binary\" Name=\"RowVer\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" ConcurrencyMode=\"Fixed\" />"},
    
                { "<Property Type=\"Binary\" Name=\"rowver\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" />",
                  "<Property Type=\"Binary\" Name=\"rowver\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" ConcurrencyMode=\"Fixed\" />"},
            };
    
            static void Main(string[] args)
            {
                // find all .edmx
                string directoryPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
                foreach (var file in Directory.GetFiles(directoryPath))
                {
                    // only edmx
                    if (!file.EndsWith(".edmx"))
                        continue;
    
                    // read file
                    var fileContents = System.IO.File.ReadAllText(file);
    
                    // replace lines
                    foreach (var item in replacements)
                        fileContents = fileContents.Replace(item.Key, item.Value);
    
                    // overwite file
                    System.IO.File.WriteAllText(file, fileContents);
                }
            }
        }

    • Proposed as answer by James Klett Monday, April 8, 2013 2:43 PM
    Wednesday, March 27, 2013 4:15 PM
  • I just adjusted the XSLT for a EF 6 project. The Namespace needed a change.

    In my code I am looking for columns with value "RowVersion". My database ist SQL 2008 that is making use of datatype "timestamp" rather then "rowversion".

    To transform the edmx I use msxsl.exe. A Batch file within the project does the job after updates.

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:csdl="http://schemas.microsoft.com/ado/2009/11/edm">
      <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
      <xsl:template match="@*|node()">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:template>
      <xsl:template match="csdl:Property[@Name='RowVersion']">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
          <xsl:attribute name="ConcurrencyMode">
            <xsl:text>Fixed</xsl:text>
          </xsl:attribute>
        </xsl:copy>
      </xsl:template>
    </xsl:stylesheet>


    Karl Haak www.karlhaak.de

    Sunday, December 29, 2013 2:44 PM
  • Thank you to all the folks who contributed!  I included the Xslt that Karl and Martin created in the project that contains my edmx file and then automated its execution by specifying a BeforeBuild task inside the project file:

      <Target Name="BeforeBuild">	<Move SourceFiles="YOUR.edmx" DestinationFiles="temp.edmx" />
    	<XslTransformation XslInputPath="Utils\EnableConcurrencyCheck.xslt" XmlInputPaths="temp.edmx" OutputPaths="YOUR.edmx" />
        <Delete Files="temp.edmx" /></Target>


    • Edited by Leon_HNL Friday, March 7, 2014 12:07 AM
    Thursday, March 6, 2014 10:56 PM