Khi viết một số bài kiểm tra đơn vị cho ứng dụng của chúng tôi, tôi tình cờ gặp một số hành vi lạ trong EF6 (được thử nghiệm với 6.1 và 6.1.2): dường như không thể tạo và xóa liên tục cơ sở dữ liệu tên/cùng chuỗi kết nối) trong cùng một ngữ cảnh ứng dụng.Lặp lại việc tạo và xóa cơ sở dữ liệu trong Entity Framework
thử nghiệm thiết lập:
public class A
{
public int Id { get; set; }
public string Name { get; set; }
}
class AMap : EntityTypeConfiguration<A>
{
public AMap()
{
HasKey(a => a.Id);
Property(a => a.Name).IsRequired().IsMaxLength().HasColumnName("Name");
Property(a => a.Id).HasColumnName("ID");
}
}
public class SomeContext : DbContext
{
public SomeContext(DbConnection connection, bool ownsConnection) : base(connection, ownsConnection)
{
}
public DbSet<A> As { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new AMap());
}
}
[TestFixture]
public class BasicTest
{
private readonly HashSet<string> m_databases = new HashSet<string>();
#region SetUp/TearDown
[TestFixtureSetUp]
public void SetUp()
{
System.Data.Entity.Database.SetInitializer(
new CreateDatabaseIfNotExists<SomeContext>());
}
[TestFixtureTearDown]
public void TearDown()
{
foreach (var database in m_databases)
{
if (!string.IsNullOrWhiteSpace(database))
DeleteDatabase(database);
}
}
#endregion
[Test]
public void RepeatedCreateDeleteSameName()
{
var dbName = Guid.NewGuid().ToString();
m_databases.Add(dbName);
for (int i = 0; i < 2; i++)
{
Assert.IsTrue(CreateDatabase(dbName), "failed to create database");
Assert.IsTrue(DeleteDatabase(dbName), "failed to delete database");
}
Console.WriteLine();
}
[Test]
public void RepeatedCreateDeleteDifferentName()
{
for (int i = 0; i < 2; i++)
{
var dbName = Guid.NewGuid().ToString();
if (m_databases.Add(dbName))
{
Assert.IsTrue(CreateDatabase(dbName), "failed to create database");
Assert.IsTrue(DeleteDatabase(dbName), "failed to delete database");
}
}
Console.WriteLine();
}
[Test]
public void RepeatedCreateDeleteReuseName()
{
var testDatabases = new HashSet<string>();
for (int i = 0; i < 3; i++)
{
var dbName = Guid.NewGuid().ToString();
if (m_databases.Add(dbName))
{
testDatabases.Add(dbName);
Assert.IsTrue(CreateDatabase(dbName), "failed to create database");
Assert.IsTrue(DeleteDatabase(dbName), "failed to delete database");
}
}
var repeatName = testDatabases.OrderBy(n => n).FirstOrDefault();
Assert.IsTrue(CreateDatabase(repeatName), "failed to create database");
Assert.IsTrue(DeleteDatabase(repeatName), "failed to delete database");
Console.WriteLine();
}
#region Helpers
private static bool CreateDatabase(string databaseName)
{
Console.Write("creating database '" + databaseName + "'...");
using (var connection = CreateConnection(CreateConnectionString(databaseName)))
{
using (var context = new SomeContext(connection, false))
{
var a = context.As.ToList(); // CompatibleWithModel must not be the first call
var result = context.Database.CompatibleWithModel(false);
Console.WriteLine(result ? "DONE" : "FAIL");
return result;
}
}
}
private static bool DeleteDatabase(string databaseName)
{
using (var connection = CreateConnection(CreateConnectionString(databaseName)))
{
if (System.Data.Entity.Database.Exists(connection))
{
Console.Write("deleting database '" + databaseName + "'...");
var result = System.Data.Entity.Database.Delete(connection);
Console.WriteLine(result ? "DONE" : "FAIL");
return result;
}
return true;
}
}
private static DbConnection CreateConnection(string connectionString)
{
return new SqlConnection(connectionString);
}
private static string CreateConnectionString(string databaseName)
{
var builder = new SqlConnectionStringBuilder
{
DataSource = "server",
InitialCatalog = databaseName,
IntegratedSecurity = false,
MultipleActiveResultSets = false,
PersistSecurityInfo = true,
UserID = "username",
Password = "password"
};
return builder.ConnectionString;
}
#endregion
}
RepeatedCreateDeleteDifferentName hoàn tất thành công, hai người kia thất bại. Theo đó, bạn không thể tạo một cơ sở dữ liệu có cùng tên, đã được sử dụng một lần trước đó. Khi cố gắng tạo cơ sở dữ liệu lần thứ hai, kiểm tra (và ứng dụng) ném một SqlException, lưu ý một đăng nhập thất bại. Đây có phải là một lỗi trong Entity Framework hoặc là hành vi này có chủ ý (với những gì giải thích)?
Tôi đã thử nghiệm điều này trên Ms SqlServer 2012 và Express 2014, chưa có trên Oracle. Nhân tiện: EF dường như có vấn đề với CompatibleWithModel là cuộc gọi đầu tiên tới cơ sở dữ liệu.
Cập nhật: Đăng một vấn đề trên tracker EF lỗi (link)
Có lý do nào mà tất cả người giúp đỡ của bạn là phương pháp tĩnh không? – timothyclifford
@timothyclifford Có lẽ vì chúng không dựa vào bất kỳ trạng thái nào, vì vậy chúng có thể được đánh dấu là tĩnh? Có lý do nào bạn phản đối phương pháp tĩnh không? – spender
Nói chung chỉ không thích các lớp/phương pháp tĩnh khi nói đến bài kiểm tra đơn vị nhưng đây chỉ là sở thích cá nhân :) xem mã có vẻ tốt, sẽ tự mình kiểm tra và xem liệu tôi có thể tìm hiểu thêm – timothyclifford