【问题标题】:How to set up an in-memory repository如何设置内存存储库
【发布时间】:2011-03-31 15:06:45
【问题描述】:

我有以下课程:

public class InMemoryRepository : IRepository
{
    public void Add(object entity)
    {
        throw new NotImplementedException();
    }

    public void Attach(object Entity)
    {
        throw new NotImplementedException();
    }

    public T Get<T>(object id)
    {
        throw new NotImplementedException();
    }

    public IList<T> GetAll<T>(string queryName)
    {
        throw new NotImplementedException();
    }

    public IList<T> GetAll<T>()
    {
        throw new NotImplementedException();
    }

    public IQueryable<T> Query<T>()
    {
        throw new NotImplementedException();
    }

    public void Remove(object entity)
    {
        throw new NotImplementedException();
    }

    public void Save(object entity)
    {
        throw new NotImplementedException();
    }
}

我们的默认存储库实现使用 NHibernate 作为后备存储,但我想实现它的内存版本,这样我就可以对域对象进行原型设计,而无需创建后备 SQL 数据库。假设所有对象都有一个 Id 属性作为主键的约定,您将如何为此实现通用内存存储?

一些我很难解决的关键点:

  • 存储库方法本身是通用的,所以我需要一些机制来自动存储和引用不同的类型。 Get&lt;TestEntity&gt;(object id) 应该能够查询所有存储的 TestEntity 实例并找到具有匹配 Id 属性的实例,但我不能直接定义 TestEntity 对象的集合,因为存储库不知道我提供什么类型直到运行时。
  • 我需要为 Query() 方法支持 LINQ to Objects。假设我能想出一个体面的方法来存储对象,这应该像返回存储对象数组 AsQueryable() 一样简单。

您将如何存储对象以满足上述要求?

【问题讨论】:

  • GetAll&lt;T&gt;(queryName) - 你能提供更多信息吗?对象本身呢?它们是否实现了某种唯一标识它们的方法?是否需要考虑层次结构/关系/图表?
  • 对于此类,请忽略该方法。该方法用于运行返回结果的存储过程(NHibernate 术语中的“命名查询”),而不是直接查询表。

标签: c# design-patterns


【解决方案1】:

基础很简单:

public class InMemoryRepository : IRepository
{
    private readonly IList<object> entities = new List<object>();

    public T Get<T>(object id)
    {
        return entities.OfType<T>.SingleOrDefault(e => e.ID == id);
    }

    public IList<T> GetAll<T>()
    {
        return entities.OfType<T>.ToList();
    }

    public IQueryable<T> Query<T>()
    {
        return GetAll<T>.AsQueryable();
    }
}

但是,一旦涉及到public IList&lt;T&gt; GetAll&lt;T&gt;(string queryName),事情就变得复杂了。

您可以使用基于 SQLite 的存储库实现来进行测试。

【讨论】:

  • 我要做的唯一改变是使用 IDictionary 而不是 IList 以获得更好的性能。
  • 您还需要观察存储库是如何创建和使用的。特别是对于 ac 测试,他可能需要确保每个人都使用相同的 InMemoryRepository 实例(也许通过 IOC)。或者实体字段需要是静态的。
【解决方案2】:

我会选择为in-memory SqlLite database 配置的 NHibernate。然后您可以测试您的真实代码并确保一切正常。为 Repository 编写 mock 可能很困难,如果你更改 IRepository 接口,你将不得不重新实现你 InMemoryRepository

对我来说,拥有 NHibernate 的一大好处是可以使用内存数据库进行测试。

【讨论】:

  • 您必须确保所有字段类型都适用于这两种类型。有时他们不会。如果他使用 MySQL for DB,它有自己的内存类型,比 SQLLite 更容易使用
  • 是的,您说得对,字段类型可能存在问题。我不知道内存中的 MySQL db,但如果有这样的选项,那对我来说听起来非常好。
【解决方案3】:

通过 Anton 的回答,我能够修复自己的 InMemoryRepository。我已经修改它以匹配问题中的类:

private readonly ConcurrentDictionary<Type, List<object>> ObjectList = new ConcurrentDictionary<Type, List<object>>();

public int Add<T>(T obj) where T : IIdentifier
{
    // instantiate if list does not exist for this object type
    if (!ObjectList.ContainsKey(typeof (T)))
        ObjectList[typeof(T)] = new List<object>();

    // get id
    var id = GetId<T>() + 1;

    // add object to list
    obj.Id = id;
    ObjectList[typeof(T)].Add(obj);

    return id;
}

public void Attach<T>(T obj) {
    // do not need to do anything
}

public T Get<T>(int id) where T : class, IIdentifier
{
    // check list exist
    if (!ObjectList.ContainsKey(typeof (T)))
        return null;

    return ObjectList[typeof(T)].OfType<T>().FirstOrDefault(n => n.Id == id);
}

public List<T> GetAll<T>(Func<T, bool> predicate) where T : new()
{
    // check list exist
    if (!ObjectList.ContainsKey(typeof(T)))
        return null;

    return ObjectList[typeof(T)].OfType<T>().Where(predicate).ToList();
}

public List<T> GetAll<T>()
{
    return ObjectList[typeof(T)].OfType<T>.ToList();
}

public IQueryable<T> Query<T>()
{
    return GetAll<T>.AsQueryable();
}

public int Remove<T>(int id) where T : IIdentifier
{
    // check list exist
    if (!ObjectList.ContainsKey(typeof(T)))
        return 0;

    // find object with matching id
    for (var i = 0; i < ObjectList[typeof(T)].Count; i++)
        if (ObjectList[typeof(T)].OfType<T>().ToList()[i].Id == id)
        {
            ObjectList[typeof(T)].RemoveAt(i);
            return id;
        }

    // object not found
    return 0;
}

public int Save<T>(T obj) where T : IIdentifier
{
    // check list exist
    if (!ObjectList.ContainsKey(typeof(T)))
        return 0;

    // find object with matching id
    for (var i = 0; i < ObjectList[typeof(T)].Count; i++)
        if (ObjectList[typeof(T)].OfType<T>().ToList()[i].Id == obj.Id)
        {
            ObjectList[typeof (T)][i] = obj;
            return obj.Id;
        }

    // object not found
    return 0;
}

#region Helper methods

private int GetId<T>() where T : IIdentifier
{
    return ObjectList[typeof(T)].Count == 0 ? 0 : ObjectList[typeof(T)].OfType<T>().Last().Id;
}

#endregion

【讨论】:

    【解决方案4】:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-23
      • 2011-08-16
      • 2010-10-11
      • 2021-01-28
      • 1970-01-01
      • 2019-08-20
      • 2015-11-04
      • 1970-01-01
      相关资源
      最近更新 更多