entity framework上下文6.1.3没有刷新/销毁?

在此unit testing中,我将validation内容字节列的MD5是否已正确计算,保留和提取。

但是,似乎entity framework(6.1.3)上下文未刷新/销毁,因为在原始SQL UPDATE显然生效后,但在使用新上下文获取行时未显示。

namespace UnitTests { [TestClass] public class TestDataPacketServiceDebug { [TestInitialize] public void Setup() { CommonMethods.ResetDatabase(); try { CommonMethods.ResetDataPacketDirectory(); } catch (DirectoryNotFoundException) { } } [TestCategory("DataPacketService"), TestMethod] public void TestGetLocalFilePathDebug() { // Persist a DataPacket int dataPacketId; using (var testDBContext = new TestDBContext()) { DataPacket dataPacket = new DataPacket { Content = File.ReadAllBytes(@"Resources\SampleResources.zip"), Description = "DataPacketSample consist of some random found .DLL files on disk", Name = "SampleResources", Version = "1" }; testDBContext.DataPackets.Add(dataPacket); testDBContext.SaveChanges(); dataPacketId = dataPacket.DataPacketId; } // Verify file path extraction using (var testDBContext = new TestDBContext()) { DataPacket dataPacket = DataPacketService.GetByNameAndVersion("SampleResources", "1", testDBContext); string extractedFilePath = DataPacketService.GetLocalFilePath(testDBContext, dataPacket, "EntityFramework.dll"); string validDestinationPath = String.Format(@"{0}\DataPackets\{1}_v{2}\EntityFramework.dll", AppDomain.CurrentDomain.BaseDirectory, dataPacket.Name, dataPacket.Version); Assert.AreEqual(validDestinationPath, extractedFilePath); if (File.Exists(extractedFilePath) == false) { Assert.Fail("SampleResources was not extracted correctly"); } } // When setting a breakpoint here and take a look with external SQL Browser // (eg Microsoft SQL Server Management Studio), following is in order: // Note! Not all columns are shown // ----------------------------------------------------------------------------------------------- // DataPacketId | Name | RowVersion | Content | MD5 | Version // 1 | SampleResources | NULL | 0x504B03... | 2zSV8IChaiyf0UfnezDHKg== | 1 // Manually modify MD5 field in database for MD5 verification using (var testDBContext = new TestDBContext()) { string sqlUpdate = String.Format("UPDATE dbo.DataPackets SET MD5 = 'another_MD5' WHERE DataPacketId = {0}", dataPacketId); testDBContext.Database.ExecuteSqlCommand(sqlUpdate); } // When setting a breakpoint here we can clearly see that the row has been changed: // Note! Not all columns are shown // ---------------------------------------------------------------------------------- // DataPacketId | Name | RowVersion | Content | MD5 | Version // 1 | SampleResources | NULL | 0x504B03... | another_MD5 | 1 // Verify MD5 using (var testDBContext = new TestDBContext()) { // Fetch dataPacket with modified MD5 DataPacket dataPacket = DataPacketService.GetByNameAndVersion("SampleResources", "1", testDBContext); // Verify that the raw SQL command has been successful: Assert.AreEqual("another_MD5", dataPacket.MD5); // BANG!!!!!!!!!!!!!! // Result Message: Assert.AreEqual failed. Expected:.Actual:. } } } } 

实体:

 public class DataPacket { ///  /// Identifier ///  public int DataPacketId { get; set; } ///  /// Concurrency Token ///  public byte[] RowVersion { get; set; } ///  /// Name ///  public string Name { get; set; } ///  /// Description of data packet ///  public string Description { get; set; } ///  /// Version of data packet ///  public string Version { get; set; } ///  /// MD5 of the data packet (ie MD5 of Content byte array) ///  public string MD5 { get; private set; } private byte[] content; ///  /// Byte content of the data packet (ie ///  public byte[] Content { get { return content; } set { content = value; UpdateMD5(); } } ///  /// TestCase navigation DataPacket  TestCases ///  public ICollection TestCases { get; set; } // DataPacket  TestCases ///  /// Update MD5 checksum depending on content ///  private void UpdateMD5() { if (content != null) { this.MD5 = GetMD5ForBytes(content); } } ///  /// Get MD5 checksum for content byte array ///  /// Content byte array /// MD5 checksum public static String GetMD5ForBytes(byte[] content) { if (content != null) { System.Security.Cryptography.MD5 md5Object = System.Security.Cryptography.MD5.Create(); return System.BitConverter.ToString(md5Object.ComputeHash(content)).Replace("-", ""); } return null; } } 

GetByNameAndVersion

 public static DataPacket GetByNameAndVersion(string name, string version, TestDBContext testDBContext) { IQueryable query = testDBContext.Set(); query = query.Where(t => t.Name == name).Where(t => t.Version == version); return query.Single(); } 

注意! 我正在使用localDB数据库。

它不是EF上下文问题(它按预期工作),但是DataPacket类中的测试/逻辑不正确。

您有两个相关属性,都映射到数据库表列:

 ///  /// MD5 of the data packet (ie MD5 of Content byte array) ///  public string MD5 { get; private set; } private byte[] content; ///  /// Byte content of the data packet (ie ///  public byte[] Content { get { return content; } set { content = value; UpdateMD5(); } } 

客户端C#代码只能设置Content ,而Content又会更新MD5 – 很好。 但是当EF从数据库加载实体时会发生什么? 实际上,它使用相同的属性设置器( private不是问题,因为EF使用reflection/代码生成,因此它可以在外部调用任何类型的setter)。

现在一切都取决于调用setter的顺序 。 在您的情况下,首先调用MD5 ,然后调用Content 。 由于您的SQL命令更新了MD5列,但保留了Content不变,因此第一个setter将从数据库中设置MD5值,第二个setter将从Content更新它。 这当然导致断言报告失败。

您可以决定是否通过SQL更新数据库中的MD5列是有效操作(基本上使MD5Content不同步)。 在undefined中调用属性setter的顺序 – 当前如果你在Content属性之后移动MD5属性声明,测试将通过,但这是你不能依赖的东西。