简体   繁体   English

模拟实体框架数据库

[英]Mock Entity Framework database

I am using Entity Framework 4+. 我正在使用Entity Framework 4+。

Is it possible to automatically create some MOCK database from the schema with some random data? 是否可以使用一些随机数据从架构中自动创建一些MOCK数据库? Where ints, put ints, where strings, put some GUIDs or whatever... 在整合,投注,字符串,放置一些GUID或其他......

It would help me to debug my application a lot. 它可以帮助我调试我的应用程序很多。

Thank you, James 谢谢詹姆斯

I discovered this great tool for use with EF 4 for mocking the database. 我发现了这个与EF 4一起用于模拟数据库的好工具 Basically it is just a T4 template that creates both the "normal" EF layer and also creates a mock object and interface that can be used to test. 基本上它只是一个T4模板,可以创建“普通”EF层,还可以创建一个可用于测试的模拟对象和接口。 More documentation here . 这里有更多文档。

One caveat, though. 但有一点需要注意。 Out of the box it didn't work for me because my repository code calls SaveChanges() and other methods which are not implemented in the generated interface. 开箱即用它不适合我,因为我的存储库代码调用SaveChanges()和其他未在生成的接口中实现的方法。 I was able to get around this by extracting the interface from Microsoft's ObjectContext implementation and creating my own IObjectContext interface. 通过从Microsoft的ObjectContext实现中提取接口并创建自己的IObjectContext接口,我能够解决这个问题。 I then created a base class (for the mock) that implements this interface by simply delegating each of the calls to an injected mock. 然后我创建了一个基类(用于模拟),它通过简单地将每个调用委托给一个注入的模拟来实现这个接口。 This way I can use Moq to create that piece in my test class, while still retaining the ability to track inserts, updates, and deletes in the generated mock. 这样我就可以使用Moq在我的测试类中创建该部分,同时仍然保留在生成的模拟中跟踪插入,更新和删除的功能。

Here are my changes to the "Context" T4 template to fix this issue. 以下是我对“Context”T4模板的更改以解决此问题。 Sorry for doing this in little bits and pieces - SO didn't let me post the entire code listing because it was too long. 很抱歉这样做的一点点零碎 - 所以我没有让我发布整个代码清单,因为它太长了。

Add this code before fileManager.Process(); fileManager.Process();之前添加此代码fileManager.Process();

fileManager.StartNewFile( "IObjectContext.cs");
WriteHeader();
WriteHeaderIncludeSystem();
WriteHeaderIncludeData();
WriteHeaderIncludeContainers();
WriteNamespaceBegin( code, namespaceName );
WriteObjectContextInterface( container, code );
WriteNamespaceEnd( namespaceName );

fileManager.StartNewFile( container.Name + "Mock.ObjectContext.cs");
WriteHeader();
WriteHeaderIncludeSystem();
WriteHeaderIncludeData();
WriteHeaderIncludeContainers();
WriteNamespaceBegin( code, namespaceName );
WriteObjectContextMockBase( container, code );
WriteNamespaceEnd( namespaceName );

Add this code after the WriteInterface() block. WriteInterface()块之后添加此代码。

<#+
void WriteObjectContextInterface( EntityContainer container, CodeGenerationTools code )
{
#>
/// <summary>
/// The interface for the generic object context. This contains all of
/// the <code>ObjectContext</code> properties that are implemented in the 
/// concrete ObjectContext class. This interface was created so these members
/// can be mocked, as ObjectContext doesn't have a default public constructor.
/// </summary>
<#=Accessibility.ForType(container)#> interface IObjectContext : IDisposable
{
    void AcceptAllChanges();
    void AddObject(string entitySetName, object entity);
    TEntity ApplyCurrentValues<TEntity>(string entitySetName, TEntity currentEntity) where TEntity : class;
    TEntity ApplyOriginalValues<TEntity>(string entitySetName, TEntity originalEntity) where TEntity : class;
    void ApplyPropertyChanges(string entitySetName, object changed);
    void Attach(System.Data.Objects.DataClasses.IEntityWithKey entity);
    void AttachTo(string entitySetName, object entity);
    int? CommandTimeout { get; set; }
    DbConnection Connection { get; }
    ObjectContextOptions ContextOptions { get; }
    void CreateDatabase();
    string CreateDatabaseScript();
    EntityKey CreateEntityKey(string entitySetName, object entity);
    T CreateObject<T>() where T : class;
    ObjectSet<TEntity> CreateObjectSet<TEntity>() where TEntity : class;
    ObjectSet<TEntity> CreateObjectSet<TEntity>(string entitySetName) where TEntity : class;
    void CreateProxyTypes(IEnumerable<Type> types);
    ObjectQuery<T> CreateQuery<T>(string queryString, params ObjectParameter[] parameters);
    bool DatabaseExists();
    string DefaultContainerName { get; set; }
    void DeleteDatabase();
    void DeleteObject(object entity);
    void Detach(object entity);
    void DetectChanges();
    void Dispose();
    int ExecuteFunction(string functionName, params ObjectParameter[] parameters);
    ObjectResult<TElement> ExecuteFunction<TElement>(string functionName, params ObjectParameter[] parameters);
    ObjectResult<TElement> ExecuteFunction<TElement>(string functionName, MergeOption mergeOption, params ObjectParameter[] parameters);
    int ExecuteStoreCommand(string commandText, params object[] parameters);
    ObjectResult<TElement> ExecuteStoreQuery<TElement>(string commandText, params object[] parameters);
    ObjectResult<TEntity> ExecuteStoreQuery<TEntity>(string commandText, string entitySetName, MergeOption mergeOption, params object[] parameters);
    object GetObjectByKey(System.Data.EntityKey key);
    void LoadProperty(object entity, string navigationProperty);
    void LoadProperty(object entity, string navigationProperty, MergeOption mergeOption);
    void LoadProperty<TEntity>(TEntity entity, Expression<Func<TEntity, object>> selector);
    void LoadProperty<TEntity>(TEntity entity, Expression<Func<TEntity, object>> selector, MergeOption mergeOption);
    System.Data.Metadata.Edm.MetadataWorkspace MetadataWorkspace { get; }
    ObjectStateManager ObjectStateManager { get; }
    void Refresh(RefreshMode refreshMode, IEnumerable collection);
    void Refresh(RefreshMode refreshMode, object entity);
    int SaveChanges();
    int SaveChanges(bool acceptChangesDuringSave);
    int SaveChanges(SaveOptions options);
    ObjectResult<TElement> Translate<TElement>(DbDataReader reader);
    ObjectResult<TEntity> Translate<TEntity>(DbDataReader reader, string entitySetName, MergeOption mergeOption);
    bool TryGetObjectByKey(EntityKey key, out object value);
}
<#+
}
#>

<#+
void WriteObjectContextMockBase( EntityContainer container, CodeGenerationTools code )
{
#>
/// <summary>
/// The default concrete implementation of IObjectContext that will be used for mocking. 
/// This contains all of the <code>IObjectContext</code> members that are implemented in the 
/// concrete ObjectContext class. This class was created so these members
/// can be mocked.
/// </summary>
<#=Accessibility.ForType(container)#> abstract class ObjectContextMockBase : IObjectContext
{
    private readonly IObjectContext _objectContext;
    public ObjectContextMockBase(IObjectContext objectContext)
    {
        if (objectContext == null)
            throw new System.ArgumentNullException("objectContext");
        _objectContext = objectContext;
    }

    public virtual void AcceptAllChanges()
    {
        _objectContext.AcceptAllChanges();
    }

    public virtual void AddObject(string entitySetName, object entity)
    {
        _objectContext.AddObject(entitySetName, entity);
    }

    public virtual TEntity ApplyCurrentValues<TEntity>(string entitySetName, TEntity currentEntity) 
        where TEntity : class
    {
        return _objectContext.ApplyCurrentValues<TEntity>(entitySetName, currentEntity);
    }

    public virtual TEntity ApplyOriginalValues<TEntity>(string entitySetName, TEntity originalEntity) 
        where TEntity : class
    {
        return ApplyOriginalValues<TEntity>(entitySetName, originalEntity);
    }

    public virtual void ApplyPropertyChanges(string entitySetName, object changed)
    {
        _objectContext.ApplyPropertyChanges(entitySetName, changed);
    }

    public virtual void Attach(System.Data.Objects.DataClasses.IEntityWithKey entity)
    {
        _objectContext.Attach(entity);
    }

    public virtual void AttachTo(string entitySetName, object entity)
    {
        _objectContext.AttachTo(entitySetName, entity);
    }

    public virtual int? CommandTimeout
    {
        get { return _objectContext.CommandTimeout; }
        set { _objectContext.CommandTimeout = value; }
    }

    public virtual DbConnection Connection 
    { 
        get { return _objectContext.Connection; }
    }

    public virtual ObjectContextOptions ContextOptions
    { 
        get { return _objectContext.ContextOptions; }
    }

    public virtual void CreateDatabase()
    {
        _objectContext.CreateDatabase();
    }

    public virtual string CreateDatabaseScript()
    {
        return _objectContext.CreateDatabaseScript();
    }

    public virtual EntityKey CreateEntityKey(string entitySetName, object entity)
    {
        return _objectContext.CreateEntityKey(entitySetName, entity);
    }

    public virtual T CreateObject<T>() 
        where T : class
    {
        return _objectContext.CreateObject<T>();
    }

    public virtual ObjectSet<TEntity> CreateObjectSet<TEntity>()
        where TEntity : class
    {
        return _objectContext.CreateObjectSet<TEntity>();
    }

    public virtual ObjectSet<TEntity> CreateObjectSet<TEntity>(string entitySetName) 
        where TEntity : class
    {
        return _objectContext.CreateObjectSet<TEntity>(entitySetName);
    }

    public virtual void CreateProxyTypes(IEnumerable<Type> types)
    {
        _objectContext.CreateProxyTypes(types);
    }

    public virtual ObjectQuery<T> CreateQuery<T>(string queryString, params ObjectParameter[] parameters)
    {
        return _objectContext.CreateQuery<T>(queryString, parameters);
    }

    public virtual bool DatabaseExists()
    {
        return _objectContext.DatabaseExists();
    }

    public virtual string DefaultContainerName
    {
        get { return _objectContext.DefaultContainerName; }
        set { _objectContext.DefaultContainerName = value; }
    }

    public virtual void DeleteDatabase()
    {
        _objectContext.DeleteDatabase();
    }

    public virtual void DeleteObject(object entity)
    {
        _objectContext.DeleteObject(entity);
    }

    public virtual void Detach(object entity)
    {
        _objectContext.Detach(entity);
    }

    public virtual void DetectChanges()
    {
        _objectContext.DetectChanges();
    }

    public virtual void Dispose()
    {
        _objectContext.Dispose();
    }

    public virtual int ExecuteFunction(string functionName, params ObjectParameter[] parameters)
    {
        return _objectContext.ExecuteFunction(functionName, parameters);
    }

    public virtual ObjectResult<TElement> ExecuteFunction<TElement>(string functionName, params ObjectParameter[] parameters)
    {
        return _objectContext.ExecuteFunction<TElement>(functionName, parameters);
    }

    public virtual ObjectResult<TElement> ExecuteFunction<TElement>(string functionName, MergeOption mergeOption, params ObjectParameter[] parameters)
    {
        return _objectContext.ExecuteFunction<TElement>(functionName, mergeOption, parameters);
    }

    public virtual int ExecuteStoreCommand(string commandText, params object[] parameters)
    {
        return _objectContext.ExecuteStoreCommand(commandText, parameters);
    }

    public virtual ObjectResult<TElement> ExecuteStoreQuery<TElement>(string commandText, params object[] parameters)
    {
        return _objectContext.ExecuteStoreQuery<TElement>(commandText, parameters);
    }

    public virtual ObjectResult<TEntity> ExecuteStoreQuery<TEntity>(string commandText, string entitySetName, MergeOption mergeOption, params object[] parameters)
    {
        return _objectContext.ExecuteStoreQuery<TEntity>(commandText, entitySetName, mergeOption, parameters);
    }

    public virtual object GetObjectByKey(EntityKey key)
    {
        return _objectContext.GetObjectByKey(key);
    }

    public virtual void LoadProperty(object entity, string navigationProperty)
    {
        _objectContext.LoadProperty(entity, navigationProperty);
    }

    public virtual void LoadProperty(object entity, string navigationProperty, MergeOption mergeOption)
    {
        _objectContext.LoadProperty(entity, navigationProperty, mergeOption);
    }

    public virtual void LoadProperty<TEntity>(TEntity entity, Expression<Func<TEntity, object>> selector)
    {
        _objectContext.LoadProperty<TEntity>(entity, selector);
    }

    public virtual void LoadProperty<TEntity>(TEntity entity, Expression<Func<TEntity, object>> selector, MergeOption mergeOption)
    {
        _objectContext.LoadProperty<TEntity>(entity, selector, mergeOption);
    }

    public virtual System.Data.Metadata.Edm.MetadataWorkspace MetadataWorkspace
    {
        get { return _objectContext.MetadataWorkspace; }
    }

    public virtual ObjectStateManager ObjectStateManager
    {
        get { return _objectContext.ObjectStateManager; }
    }

    public virtual void Refresh(RefreshMode refreshMode, IEnumerable collection)
    {
        _objectContext.Refresh(refreshMode, collection);
    }

    public virtual void Refresh(RefreshMode refreshMode, object entity)
    {
        _objectContext.Refresh(refreshMode, entity);
    }

    public virtual int SaveChanges()
    {
        return _objectContext.SaveChanges();
    }

    public virtual int SaveChanges(bool acceptChangesDuringSave)
    {
        return _objectContext.SaveChanges(acceptChangesDuringSave);
    }

    public virtual int SaveChanges(SaveOptions options)
    {
        return _objectContext.SaveChanges(options);
    }

    public virtual ObjectResult<TElement> Translate<TElement>(DbDataReader reader)
    {
        return _objectContext.Translate<TElement>(reader);
    }

    public virtual ObjectResult<TEntity> Translate<TEntity>(DbDataReader reader, string entitySetName, MergeOption mergeOption)
    {
        return _objectContext.Translate<TEntity>(reader, entitySetName, mergeOption);
    }

    public virtual bool TryGetObjectByKey(EntityKey key, out object value)
    {
        return _objectContext.TryGetObjectByKey(key, out value);
    }
}
<#+
}
#>

Change the first 2 lines (the 2nd one being the curly bracket) of WriteMockContextBody() (after the comment) to WriteMockContextBody() (注释后)的前两行(第二行是大括号) WriteMockContextBody()

<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#>Mock : ObjectContextMockBase, I<#=code.Escape(container)#>
{
    public <#=code.Escape(container)#>Mock(IObjectContext objectContext)
        : base(objectContext)
    {
    }

Change the first line of WriteInterface() (after the comment) to WriteInterface()的第一行(在注释之后)更改为

<#=Accessibility.ForType(container)#> interface I<#=code.Escape(container)#> : IObjectContext

I should also note that I haven't done much testing with this yet, but I did do some basic verifications to ensure it functions. 我还应该注意到,我还没有做过多少测试,但我确实做了一些基本的验证以确保它的功能。

See Rab Hallett's blog titled ADO.NET Mocking Context Generator: Visual Studio 2010 Template 请参阅Rab Hallett的博客,题为“ ADO.NET模拟上下文生成器:Visual Studio 2010模板”

Here Rab uses a T4 template to create the interface for EF. Rab使用T4模板为EF创建界面。

这是有助于生成测试数据的库 - http://autopoco.codeplex.com/

You can check out this thread about Visual Studio for Database Professionals. 您可以查看有关Visual Studio for Database Professionals的此主题 Or RedGate has a similar tool . 或者RedGate有一个类似的工具 I don't know of any free tools that would do this. 我不知道有任何免费工具可以做到这一点。

Goto this link and have a look at this section "Seeding Initial Data in Automatically Created Databases" 转到此链接并查看本节“在自动创建的数据库中播种初始数据”

http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx

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

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