How to validate a XML file against a XSD file, including the referenced schemas by the XSD file in C#.

If you want to validate an XML file against a XSD file and use the XSD schemas referenced by the XSD file in the validation, you can use the following C# code:

 

using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Research.Rli
{
/// <summary>
/// Tests in this class are only used to analyse and research code.
/// It is not intended to contain real integration tests.
/// </summary>
[TestClass]
public class RliResearchTester
{
public RliResearchTester()
{
}
/// <summary>
/// Test xml validation against a XSD file.
/// </summary>
[TestMethod]
public void ValidateXmlTest()
{
ValidateXml(@"C:\Data\Input.xml", @"C:\Data\ValidationSchema.xsd");
}
/// <summary>
/// Validates a xml file (found at the given xmlFilePath) to a XSD file (found at the given xsdFilePath).
/// </summary>
/// <param name="xmlFilePath">The xml file to validate.</param>
/// <param name="xsdFilePath">The xsd file used in the validation.</param>
/// <exception cref="ArgumentNullException">
/// Throws an ArgumentNullException, when xmlFilePath is null, empty or contains only white spaces.
/// </exception>
/// <exception cref="ArgumentNullException">
/// Throws an ArgumentNullException, when xsdFilePath is null, empty or contains only white spaces.
/// </exception>
/// <exception cref="ArgumentException">Throws an ArgumentException, when xmlFilePath does not exist.</exception>
/// <exception cref="ArgumentException">Throws an ArgumentException, when xsdFilePath does not exist.</exception>
/// <remarks>
/// - Includes schemas referenced by the given xsd file (recursively).
/// </remarks>
public void ValidateXml(string xmlFilePath, string xsdFilePath)
{
if (string.IsNullOrWhiteSpace(xmlFilePath)) { throw new ArgumentNullException("xmlFilePath"); }
if (string.IsNullOrWhiteSpace(xsdFilePath)) { throw new ArgumentNullException("xsdFilePath"); }
if (!File.Exists(xmlFilePath))
{
throw new ArgumentException(string.Format("File [{0}] not found.", xmlFilePath));
}
if (!File.Exists(xsdFilePath))
{
throw new ArgumentException(string.Format("File [{0}] not found.", xsdFilePath));
}
var schemas = new XmlSchemaSet();
// Use the target namespace specified in the XSD file. 
schemas.Add(null, xsdFilePath);
var readerSettings = new XmlReaderSettings();
// Validate the xml file to an XSD file not an DTD or XDR.
readerSettings.ValidationType = ValidationType.Schema;
// Include schemas referenced by the given xsd file (recursively) in the validation proces.
readerSettings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
// Warnings will fire the ValidationEventHandler function.
readerSettings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
readerSettings.Schemas.Add(schemas);
// The function [ValidationEventHandler] will be used to handle all validation errors / warnings.
readerSettings.ValidationEventHandler += ValidationEventHandler;
using (var xmlReader = XmlReader.Create(xmlFilePath, readerSettings))
{
while (xmlReader.Read()) { }    // Validate XML file.
}
}
/// <summary>
/// This event will fire on every XML validation error / warning.
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
public void ValidationEventHandler(object sender, ValidationEventArgs args)
{
Console.WriteLine(string.Format("",
new object[] { args.Exception, args.Exception.LineNumber, args.Exception.LinePosition }));
}
}
}

How to name primary key and foreign key constraints, when creating a table with T-SQL.

When trouble shouting error’s thrown by T-SQL, naming your primary and foreign keys, proves to be handy.

When creating tables with T-SQL, I use the naming format PK_MyTable_MyColumn1_MyColumn2 and FK_MyTable_MyColumn3_MyColumn4:

if object_id('[dbo].[Address]') is null
begin
create table [dbo].[Address]
(
Id        int not null  identity(1,1) constraint PK_Address_Id primary key
)
end
if object_id('[dbo].[Person]') is null
begin
create table [dbo].[Person]
(
Id           int not null  identity(1,1) constraint PK_Person_Id primary key,
AddressId    int not null constraint FK_Person_AddressId foreign key references [dbo].[Address](Id)
)
end

How to change the *.mdf and *.ldf location of an online Microsoft SQL Server LocalDb database in a Microsoft Visual Studio 2010 test.

For testing purposes it is possible to copy a new localdb database to your output directory and start using this localdb database. For more information see my previous post: https://www.roelvanlisdonk.nl/?p=2607

It is possible that a previous tests run did not cleanup it’s copy of the localdb database. Now if you want to attach an new localdb database with the same name, the attach will fail. There are several options you have to fix this error. I decided to just "re-use" the existing database, just changing the *.mdf and *.ldf file location.

 

The following code can help you do just that:

using System.Data.SqlClient;
using System.IO;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
namespace Test.Research
{
/// <summary>
/// Tests in this class are only used to analyse and research code.
/// It is not intended to contain real integration tests.
/// </summary>
[TestClass]
public class RliResearchTester
{
/// <summary>
/// Changes the *.mdf and *.ldf file location for the given LocalDb database, when it exists.
/// </summary>
/// <remarks>
/// It expects the mdf file name to be in the format [DatabaseName.mdf].
/// It expects the ldf file name to be in the format [Databasename_log.ldf].
/// It expects the old mdf file name to be equal to the new mdf file name (only the file location will change).
/// It expects the old ldf file name to be equal to the new ldf file name (only the file location will change).
/// </remarks>
[TestMethod]
public void ChangeMdfAndLdfLocationForExistingLocalDb()
{
string dataSource = @"(localdb)\V11.0";
string databaseName = "MyReserachDb";
string folderContainingNewDatabaseFiles = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string oldMdfFilePath = GetMdfFilePath(dataSource, databaseName);
if (!string.IsNullOrWhiteSpace(oldMdfFilePath))
{
ModifyDatabaseFilePaths(dataSource, databaseName, folderContainingNewDatabaseFiles);
}
}
/// <summary>
/// Gets the full physical mdf filepath, based on the supplied data soruce (Servername\Instancename) and database name.
/// </summary>
/// <param name="dataSource">SQL Server instance in the format (ServerName\InstanceName)</param>
/// <param name="databaseName">Name of the database.</param>
/// <returns>
/// Databse found:     Returns the full physical mdf filepath.
/// Databse not found: Returns null.
/// </returns>
/// <remarks>
/// Uses windows authentication to connect.
/// This function does not take into account, the fact that a mdf file name can be different, then the [DatabaseName.mdf].
/// </remarks>
public string GetMdfFilePath(string dataSource, string databaseName)
{
string result = null;
string mdfName = databaseName;
using (var connection = new SqlConnection(string.Format(@"Data Source=""{0}"";Initial Catalog=master;Integrated Security=True;", dataSource)))
using (var command = new SqlCommand("select top 1 physical_name from sys.master_files where name = @MdfName", connection))
{
command.Parameters.Add(new SqlParameter("MdfName", mdfName));
connection.Open();
result = command.ExecuteScalar() as string;
}
return result;
}
/// <summary>
/// Modifies the *.mdf and *.ldf database file locations of an existing online database.
/// </summary>
/// <param name="dataSource">SQL Server instance in the format (ServerName\InstanceName)</param>
/// <param name="databaseName">Name of the database.</param>
/// <param name="folderContainingNewDatabaseFiles">The folder containing new database files.</param>
/// <remarks>
/// - Uses windows authentication to connect.
/// - Drops all existing database connections, by using [with rollback immediate] on the [set offline].
/// - Forces the database to use the new files, by using [set offline] and [set online].
/// - It expects the mdf file name to be in the format [DatabaseName.mdf].
/// - It expects the ldf file name to be in the format [Databasename_log.ldf].
/// - It expects the old mdf file name to be equal to the new mdf file name (only the file location will change).
/// - It expects the old ldf file name to be equal to the new ldf file name (only the file location will change).
/// </remarks>
public void ModifyDatabaseFilePaths(string dataSource, string databaseName, string folderContainingNewDatabaseFiles)
{
string mdfName = databaseName;
string ldfName = string.Format("{0}_log", databaseName);
string newMdfFileLocation = Path.Combine(folderContainingNewDatabaseFiles, string.Format("{0}.mdf", mdfName));
string newLdfFileLocation = Path.Combine(folderContainingNewDatabaseFiles, string.Format("{0}.ldf", ldfName));
string query = string.Format(@"
alter database {0} modify file (name = {1}, filename = '{3}');
alter database {0} modify file (name = {2}, filename = '{4}');
alter database {0} set offline with rollback immediate;
alter database {0} set online;", 
new string[] { databaseName, mdfName, ldfName, newMdfFileLocation, newLdfFileLocation });
using (var connection = new SqlConnection(string.Format(@"Data Source=""{0}"";Initial Catalog=master;Integrated Security=True;", dataSource)))
using (var command = new SqlCommand(query, connection))
{
connection.Open();
command.ExecuteNonQuery();
}
}
}
}

Using SQL Server 2012 LocalDb in VS11 and VS2010 for testing.

To create high quality LOB applications unit tests and integration tests are mandatory. You want to run these integration tests and unit tests on your continuous integration server. The problem with integration tests or testing things like stored procedures you want your database filled with consistent test data and you don’t want multiple tests ore multiple builds have impact on each other. To prevent this, you can run a SQL script that deploys a new database for each test, creating a unique database with test data and after running the tests delete this database. This is a whole lot of work and it can be simplified and improving performance by using a LocalDb file, instead of a SQL Server test instance.

 

LocalDb benefits

– No SQL Server installation for running integration tests or testing stored procedures, on your local dev machine or on the continuous build server.

– Improved performance for tests (uses share memory, instead of TCP / IP to connect to database).

– Increase in speed of development.

– No code (T-SQL, EF etc.) changes, because LocalDb contains the same functionality as the full blown SQL Server (same code base).

– No configuration

– Supports AttachDBFileName, this means you can automatically copy the LocalDb (containing you test data) to your test output folder, by using the standard [DeploymentItems] and then let the integration tests use this file to connect to.

– It’s FREE

– Works on >= Visual Studio 2010

 

LocalDb disadvantages

– Requires .NET 4.0.2

 

Instructions for VS11

To show the usage of the Microsoft SQL Server 2012 LocalDb file in a Microsoft Visual Studio test project, you can use the following instructions:

 

Create a Microsoft Visual Studio Solution

image

 

Create a resources project, containing the LocalDb file

image

Add a Microsoft SQL Server 2012 LocalDb file

Add > New Item… > Visual C# Items > Data > Service-based Database:

image

Just click Next > Next > Finish:

image

image

Remove the dataset: LocalDbDemoDataSet.xsd

 

Add a Unit test project, containing tests, that connect to the LocalDb file

image

 

Add a *.testsetting file to you solution

image

 

Enable DeploymentItems and add LocalDb to deployment items

image

This will copy the LocalDbDemo.mdf and ldf file to the Microsoft Visual Studio output folder. So the only code that can interfere with your test data and test database, are your own tests. If you want a clean database not for each test run, but foreach test, then you can use the DeploymentItem attribute on your test or test class. 

 

Add a unit test class [LocalDbTester] to the test project

By using the [AttachDbFilename] property in your connection string, the test will automatically attach the *.mdf and *.ldf file to the LocalDb engine. Note: without specifying the Initial Catalog or Database property, the name of the database will include the full path to the *.mdf file, in most cases this is not what you want.

 

Final solution setup, should look like:

image

Run the test

The output is a succeeded test, demonstrating connecting to the LocalDb *.mdf file, within a Microsoft Visual Studio 11 test project.

using System;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace LocalDbDemo.Test
{
[TestClass]
public class LocalDbTester
{
[TestMethod]
public void ShowLocalDbData()
{
string mdfFilename = "LocalDbDemo.mdf";
string outputFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string attachDbFilename = Path.Combine(outputFolder, mdfFilename);
string connectionString = string.Format(@"Data Source=(LocalDB)\v11.0;Initial Catalog=LocalDbDemo;AttachDbFilename=""{0}"";Integrated Security=True", attachDbFilename);
using (var connection = new SqlConnection(connectionString))
using (var command = new SqlCommand("select * from Person", connection))
using (var adapter = new SqlDataAdapter(command))
{
var table = new DataTable();
int count = adapter.Fill(table);
Assert.IsTrue(count > 0);
}
}
}
}

Instructions for VS2010

The instructions for VS11, also apply for Microsoft Visual Studio 2010, but there are some prerequisites:

– Microsoft Visual Studio 2010 SP1, should be installed (http://www.microsoft.com/download/en/details.aspx?id=23691).

– Microsoft .NET 4.0.2 design-time update (for developer machine http://www.microsoft.com/download/en/details.aspx?id=27759).

– Microsoft .NET 4.0.2 run-time update (for machines that do not contain Microsoft Visual Studio 2010 http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=27756).

– SqlLocalDb.msi (http://msdn.microsoft.com/en-us/evalcenter/hh230763):

 

image

 

 

Some extra instructions for Visual Studio 2010

Creating a LocalDb file in C:\Users\<UserAccountName>…, use the Server Explorer:

image

image

A LocalDbDemo.mdf and LocalDbDemo.ldf file will be created in the folder C:\Users\<UserAccountName>…

These files can now be copied and included in the LocalDbDemo.Resource project.

Adding a new LocalDb file by using the Add New Item > Data > Service-based Database, will not work in VS2010:

image

 

Managing the localdb (creating tables, stored procedures etc.), should be done by using Microsoft SQL Server 2012 Management studio. Just connect to (localdb\V11.0) and then attach the created localdb file.

 

End results in Microsoft Visual 2010

This screen dump shows the use of a LocalDb.mdf file in a Microsoft Visual Studio 2010 unit test.

image

So using Microsoft SQL Server 2012 LocalDb in a Microsoft Visual Studio 2010 unit test works.

 

Notes

One of the big disadvantages of using Microsoft Visual Studio 2010 instead of Microsoft Visual Studio 11, is that the LocalDb.mdf file can’t be edited / designed by using Microsoft Visual Studio 2010 directly, you must use Microsoft SQL Server 2012 Management Studio to edit / design the database.

If you encounter attach error, because the localdb is already attached, read my other post on changing the database file paths of an online localdb databaes (https://www.roelvanlisdonk.nl/?p=2636).

 

More information on LocalDb:

http://channel9.msdn.com/posts/SQL11UPD03-REC-07

http://channel9.msdn.com/posts/SQL11UPD04-REC-02

How to use content files from another project in a Visual Studio unit test, by using DeploymentItems.

 

To access a file from another project in a Microsoft Visual Studio unit test, without specifying the absolute path, you can use DeploymentItems.

 

DeploymentItems

DeploymentItems are files that will be copied to the output folder of the test. Microsoft Visual Studio tests are not run in the bin directory, but for each test a new directory is created, like: C:\Temp\Rli.Common\TestResults\rlisdonk_L084 2012-03-13 09_30_34\Out. DeploymentItems will be copied to this directory.

 

Enable DeploymentItems

Double click on the Solution Item > Local.testsettings in the Solution Explorer > Click on Deployment > check the "Enable deployment" checkbox > Apply > Close.

image

 

Add DeploymentItems

Now you can add DeploymentItems to your TestClass or TestMethod:

using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Rli.TestProject
{
[TestClass]
[DeploymentItem(@"Rli.Common\Settings.xml")]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
Assert.IsTrue(System.IO.File.Exists("Settings.xml"));
}
}
}

The file [Settings.xml] in the Rli.Common project, can now be accessed in the unit test "UnitTest1.TestMethod1" in the Microsoft Visual Studio test project "Rli.TestProject".

 

image

 

 

Notes

  • The relative path used in [DeploymentItem(@"Rli.Common\Settings.xml")]  is relative to the Solution Folder!
  • If you want the file to be copied for all tests, you can add the file to the deployment files in the Local.testsettings. If you add the file to the deployment files, you don’t have to specify the DeploymetItem attribute on your TestClass or TestMethod, because the files will automatically be deploy to the test output folder:
  • image
  • If you only want to use a content file from another project, the test project does not have to reference the other project.
  • Adding files as linked content files (Project > Add Existing Item… > browse to the file, select it and click on Add As Link) and setting the file property "Copy to Output Directory" property to "Copy Always" will not work in this case. You will need to use DeploymentItems.
  • If you are using TFS with build templates, make sure the setting "TestSettings File" is set to a testsettings file that has Deployment files set to enabled. As testsettings file you can use, the Local.testsettings edited above.

image

How to convert a bitmap into a 1bpp monochrome TIFF in C#

If you want to convert a bitmap into a TIFF, than then you can use the code:

using (System.Drawing.Bitmap sourceBitmap = new System.Drawing.Bitmap(@"C:\Temp\Source.bmp"))
{
string outputFileName = @"C:\Temp\Destination.tiff";
if (System.IO.File.Exists(outputFileName))
{
System.IO.File.Delete(outputFileName);
}
sourceBitmap.Save(outputFileName, System.Drawing.Imaging.ImageFormat.Tiff);
}

If you want to convert a bitmap to a 1bpp monochrome TIFF in C#, I found 4 options:

1. http://www.bobpowell.net/onebit.htm ( no P-Invoke required, but not as fast as other methods )

2. http://social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/9757dc94-11f3-4b30-a85c-cb9145eba12d (only when you are using WPF)

3. http://www.news2news.com/vfp/?example=493&ver=vcs&PHPSESSID=35494364de9987dfd2a9f3fe18f17565 (less code then option 4, but did not have time to investigate)

4. http://www.wischik.com/lu/programmer/1bpp.html

 

For the last options I cleanup some code:

using (System.Drawing.Bitmap sourceBitmap = new System.Drawing.Bitmap(@"C:\Temp\Source.bmp"))
{
using (Bitmap destinationBitmap = sourceBitmap.ConvertToMonochromeTiff())
{
string outputFileName = @"C:\Temp\Destination.tiff";
if (System.IO.File.Exists(outputFileName))
{
System.IO.File.Delete(outputFileName);
}
destinationBitmap.Save(outputFileName);
}
}

Where the ConvertToMonochromeTiff is an extension method to the System.Drawing.Bitmap type:

 

using System;
using System.Drawing;
namespace Rli.Extensions
{
/// <summary>
/// Contains extensions methods to the System.Drawing.Bitmap type.
/// </summary>
public static class BitmapExtensions
{
#region P-Invoke
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern IntPtr GetDC(IntPtr hwnd);
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleDC(IntPtr hdc);
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc);
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern int DeleteDC(IntPtr hdc);
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern int BitBlt(IntPtr hdcDst, int xDst, int yDst, int w, int h, IntPtr hdcSrc, int xSrc, int ySrc, int rop);
static int SRCCOPY = 0x00CC0020;
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
static extern IntPtr CreateDIBSection(IntPtr hdc, ref BITMAPINFO bmi, uint Usage, out IntPtr bits, IntPtr hSection, uint dwOffset);
static uint BI_RGB = 0;
static uint DIB_RGB_COLORS = 0;
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct BITMAPINFO
{
public uint biSize;
public int biWidth, biHeight;
public short biPlanes, biBitCount;
public uint biCompression, biSizeImage;
public int biXPelsPerMeter, biYPelsPerMeter;
public uint biClrUsed, biClrImportant;
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 256)]
public uint[] cols;
}
static uint MAKERGB(int r, int g, int b)
{
return ((uint)(b & 255)) | ((uint)((r & 255) << 8)) | ((uint)((g & 255) << 16));
}
#endregion
/// <summary>
/// Converts the given bitmap to a monochrome tiff bitmap.
/// </summary>
/// <param name="sourceBitmap">The source bitmap.</param>
/// <returns></returns>
public static Bitmap ConvertToMonochromeTiff(this Bitmap sourceBitmap)
{
Bitmap destination = null;
int bpp = 1;                                                            // Amount of bits to use in pallet, for monochrome use 1 bit (0 = black, 1 = white).
uint ncols = (uint)1 << bpp;                                            // Use 2 colours (black and white) for monochrome tiff.
int width = sourceBitmap.Width;
int height = sourceBitmap.Height;
uint size = (uint)(((width + 7) & 0xFFFFFFF8) * height / 8);
uint[] pallet = new uint[256];                                          // Pallet has a fixed size 256, even when we are using fewer colours.
pallet[0] = MAKERGB(0, 0, 0);                                           // Create black pixel.
pallet[1] = MAKERGB(255, 255, 255);                                     // Create white pixel.
BITMAPINFO bmi = new BITMAPINFO()                                       // Create unmanaged monochrome bitmapinfo.
{
biSize = 40,                                                        // The size of the BITMAPHEADERINFO struct.
biWidth = width,
biHeight = height,
biPlanes = 1,
biBitCount = (short)bpp,                                            // Amount of bits per pixel (1 for monochrome).
biCompression = BI_RGB,
biSizeImage = size,
biXPelsPerMeter = 1000000,
biYPelsPerMeter = 1000000,
biClrUsed = ncols,
biClrImportant = ncols,
cols = pallet
};
IntPtr sourceHbitmap = sourceBitmap.GetHbitmap();                       // Convert bitmap to unmanaged HBitmap.
IntPtr bits0;                                                           // Pointer to the raw bits that make up the bitmap.
IntPtr destinationHbitmap = CreateDIBSection
(
IntPtr.Zero,
ref bmi,
DIB_RGB_COLORS,
out bits0,
IntPtr.Zero,
0
);                                                                      // Create the indexed bitmap.
IntPtr screenDC = GetDC(IntPtr.Zero);                                   // Obtain the DC (= GDI equivalent of "Graphics" in GDI+) for the screen.
IntPtr sourceDC = CreateCompatibleDC(screenDC);                         // Create a DC for the original hbitmap.
SelectObject(sourceDC, sourceHbitmap);
IntPtr destinationDC = CreateCompatibleDC(screenDC);                    // Create a DC for the monochrome hbitmap.
SelectObject(destinationDC, destinationHbitmap);
BitBlt(destinationDC, 0, 0, width, height, sourceDC, 0, 0, SRCCOPY);    // Use GDI's BitBlt function to copy from original hbitmap into monocrhome bitmap.
destination = System.Drawing.Bitmap.FromHbitmap(destinationHbitmap);    // Convert this monochrome hbitmap back into a Bitmap.
// Cleanup.
DeleteDC(sourceDC);
DeleteDC(destinationDC);
ReleaseDC(IntPtr.Zero, screenDC);
DeleteObject(sourceHbitmap);
DeleteObject(destinationHbitmap);
return destination;
}
}
}

Tip for Windows 8 CP users, what to do when the start screen doesn’t respond any more.

I ran into some cases, where the Windows 8 CP start screen didn’t respond any more. When I clicked on a title, the tile would show the “button click transformation”, but would not start any app. It would not even show the desktop or by pressing CTRL + SHIFT + ESC show the task manager. The only thing that worked for me, without rebooting the system, was sign out and sign in again. The virtual machine that I was running would still be running after the sign in, sign out action.

How to update an entity in the database, when state tracking is disabled in Entity Framework 4.3

When you disable state tracking in Entity Framework 4.3, for performance improvements (and you know what you’re doing Winking smile), by setting: DbContext.Configuration.AutoDetectChangesEnabled = false , then you are responsible for your own state tracking on entities.

 

The process of updating an entity, involves 3 steps:

1. Setting the EntityState to Modified.

2. Save changes to database.

3. Setting the EntityState to Unchanged.

 

Code

// Set entity to modified, so the entity will be updated in the database.
_dbContext.Entry(imageInfo).State = System.Data.EntityState.Modified;
// Save changes to database.
_dbContext.SaveChanges();
// Set entity to unchanged, so the entity will be not be updated in future calls to _dbContext.SaveChanges().
_dbContext.Entry(imageInfo).State = System.Data.EntityState.Unchanged;    

Notes

1. Where _dbConext is an instance of the DbContext class.

2. If you don’t set the Entity.State to Modified, no changes will be persisted to the database.

3. If you don’t set the Entity.State to Unchanged after SaveChanges(), future calls to SaveChanges() will repeat the update for this entity.