在 Entity Framework 4 中对动态查询进行单元测试

发布于 2024-10-04 23:57:13 字数 124 浏览 7 评论 0原文

当使用实体框架 4.0 实现工作单元模式时,正确的设计是什么才能提供使用对象上下文的 CreateQuery 方法创建动态查询的能力?我所说的正确是指以某种方式进行设计,以便我可以在模拟对象的单元测试中使用它。

谢谢。

When implementing a Unit of Work pattern with entity framework 4.0, what is the correct design to give the ability to create dynamic queries with CreateQuery method of the object context? And by correct I mean designing somehow that I can use it in unit test with mock objects.

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

旧情别恋 2024-10-11 23:57:13

不知道“正确”是什么意思,这取决于您的情况,但一般答案是您将需要一些可以在测试期间替换的抽象。为了获得一些灵感,这里是我们使用的(我们使用自跟踪 poco 实体)

/// <summary>
/// Object context interface for abstracting the service layer from the
/// implementation details of object storage.
/// </summary>
public interface IObjectContext : IDisposable
{
    /// <summary>
    /// Returns the entity objects of the given type known by this object context.
    /// </summary>
    /// <typeparam name="TEntity">The type of the entity.</typeparam>
    /// <returns>The instances of the given type already loaded into this object context</returns>
    IEnumerable<TEntity> GetManagedEntities<TEntity>() where TEntity : EntityBase;

    /// <summary>
    /// Creates an object set for the provided entity type.
    /// </summary>
    /// <typeparam name="TEntity">The type of the entity.</typeparam>
    /// <returns></returns>
    IObjectSet<TEntity> CreateObjectSet<TEntity>() where TEntity : EntityBase;

    /// <summary>
    /// Applies the changes made to the provided entity object graph to this object context.
    /// </summary>
    /// <typeparam name="TEntity">The type of entity (inferred).</typeparam>
    /// <param name="entity">The entity object graph that has been modified.</param>
    void ApplyChanges<TEntity>(TEntity entity) where TEntity : EntityBase, IObjectWithChangeTracker;

    /// <summary>
    /// Saves the changes known by this object context instance to the database.
    /// </summary>
    void Save();

    /// <summary>
    /// Creates a new logical unit of work spanning a single business transaction.
    /// </summary>
    IUnitOfWork CreateUnitOfWork();

    /// <summary>
    /// Creates a new logical unit of work spanning a single business transaction.
    /// </summary>
    /// <param name="isolationLevel">The transaction isolation level used by the
    /// unit of work ambient transaction.</param>
    /// <returns></returns>
    IUnitOfWork CreateUnitOfWork(IsolationLevel isolationLevel);
}

和抽象事务,

/// <summary>
/// Interface abstraction for a unit of work, aka all persistent work spanning a single
/// business transaction and to be performed in unity.
/// </summary>
/// <remarks>Used to support outer and inner units of work where one outer UoW may consist
/// of multiple nested inner UoW instances and have all of them share a transaction.</remarks>
public interface IUnitOfWork : IDisposable
{
    /// <summary>
    /// Gets the transaction isolation level used by the unit of work ambient transaction.
    /// </summary>
    /// <value>The isolation level.</value>
    IsolationLevel IsolationLevel { get; }

    /// <summary>
    /// Gets the transaction timeout time span used by the unit of work ambient transaction.
    /// </summary>
    /// <value>The transaction timeout duration.</value>
    TimeSpan TransactionTimeout { get; }

    /// <summary>
    /// Completes the unit of work that this instance represents.
    /// </summary>
    /// <remarks>
    /// For an outer unit of work, will persist all changes represented by this business
    /// transaction and will then signal the ambient transaction in use as complete.
    /// For an inner unit of work, will signal itself as completed to the outer unit of
    /// work that it is part of.
    /// </remarks>
    void Complete();
}

然后修改对象上下文生成代码以支持这些接口 + 根据您的需求实现您的 UoW(为简洁起见,我们省略了实现)。华泰

Don't know what you mean by "correct" it depends on your situation, but the general answer is that you will need some abstractions that can be replaced during test. For some inspiration, here is what we use (we use self tracking poco entities)

/// <summary>
/// Object context interface for abstracting the service layer from the
/// implementation details of object storage.
/// </summary>
public interface IObjectContext : IDisposable
{
    /// <summary>
    /// Returns the entity objects of the given type known by this object context.
    /// </summary>
    /// <typeparam name="TEntity">The type of the entity.</typeparam>
    /// <returns>The instances of the given type already loaded into this object context</returns>
    IEnumerable<TEntity> GetManagedEntities<TEntity>() where TEntity : EntityBase;

    /// <summary>
    /// Creates an object set for the provided entity type.
    /// </summary>
    /// <typeparam name="TEntity">The type of the entity.</typeparam>
    /// <returns></returns>
    IObjectSet<TEntity> CreateObjectSet<TEntity>() where TEntity : EntityBase;

    /// <summary>
    /// Applies the changes made to the provided entity object graph to this object context.
    /// </summary>
    /// <typeparam name="TEntity">The type of entity (inferred).</typeparam>
    /// <param name="entity">The entity object graph that has been modified.</param>
    void ApplyChanges<TEntity>(TEntity entity) where TEntity : EntityBase, IObjectWithChangeTracker;

    /// <summary>
    /// Saves the changes known by this object context instance to the database.
    /// </summary>
    void Save();

    /// <summary>
    /// Creates a new logical unit of work spanning a single business transaction.
    /// </summary>
    IUnitOfWork CreateUnitOfWork();

    /// <summary>
    /// Creates a new logical unit of work spanning a single business transaction.
    /// </summary>
    /// <param name="isolationLevel">The transaction isolation level used by the
    /// unit of work ambient transaction.</param>
    /// <returns></returns>
    IUnitOfWork CreateUnitOfWork(IsolationLevel isolationLevel);
}

and for abstracting transactions

/// <summary>
/// Interface abstraction for a unit of work, aka all persistent work spanning a single
/// business transaction and to be performed in unity.
/// </summary>
/// <remarks>Used to support outer and inner units of work where one outer UoW may consist
/// of multiple nested inner UoW instances and have all of them share a transaction.</remarks>
public interface IUnitOfWork : IDisposable
{
    /// <summary>
    /// Gets the transaction isolation level used by the unit of work ambient transaction.
    /// </summary>
    /// <value>The isolation level.</value>
    IsolationLevel IsolationLevel { get; }

    /// <summary>
    /// Gets the transaction timeout time span used by the unit of work ambient transaction.
    /// </summary>
    /// <value>The transaction timeout duration.</value>
    TimeSpan TransactionTimeout { get; }

    /// <summary>
    /// Completes the unit of work that this instance represents.
    /// </summary>
    /// <remarks>
    /// For an outer unit of work, will persist all changes represented by this business
    /// transaction and will then signal the ambient transaction in use as complete.
    /// For an inner unit of work, will signal itself as completed to the outer unit of
    /// work that it is part of.
    /// </remarks>
    void Complete();
}

then modify the object context generation code to support these interfaces + implement your UoW according to your needs (our implementation omitted for brevity). HTH

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文