实例的策略模式基于类型变量的不同存储库

时间:2011-11-29 16:07:52

标签: c# asp.net-mvc-3 entity-framework-4 ef-code-first wiki

我正在开发一个wiki项目。 MVC3 + EF4代码优先。

我模型中的所有类都继承自主“EditBase”类。这可以确保它们都具有ID,用户名和CreatedDate。它还帮助我为基本CRUD创建通用存储库。

我希望定义一个名为AbuseReport的新实体来处理不正确/不真实内容的标记:

public class AbuseReport : EditBase
{
    public DateTime DateReported { get; set; }
    public string EntityType { get; set; }
    public int EntityId { get; set; }
    public int ReportTypeId { get; set; }
    public ReportType ReportType 
    {
        get { return (ReportType) this.ReportTypeId; }
        set { this.ReportTypeId = (int) value; }
    }
    public string Description { get; set; }
}

从AbuseReport对象的信息开始,检索存储在数据库中的实体的最简单方法是什么?我不能使用外键,因为报告可以引用项目中的任何实体。

我需要打电话给这样的话:

Type modelType;
entityDictionary.TryGetValue(entityName, out modelType);
var rep = new Repository<modelType>();

2 个答案:

答案 0 :(得分:1)

我不完全确定我理解你的目标,但我相信问题是如何采用开放的泛型类型并使其成为封闭的泛型类型。

如果是这种情况,试试这个反思魔法:

var repository = Activator.CreateInstance(typeof(Repository<>).MakeGenericType(modelType));

或者如果您在这些行中使用容器或其他内容,请从容器中的MakeGenericType调用中解析生成的闭合泛型类型,而不是使用Activator.CreateInstance。无论哪种方式,你应该结束你想要的实例。

是否与您所寻找的一致?

编辑: 在回答Olivier Jacot-Descombes的问题时,这里有一些想法和代码:

理想情况下,我会使用您选择的ioc容器的一些内置功能或类似此反射代码的东西来注册带有容器的开放泛型类型或一些选择封闭类型(容器的功能各不相同)。然后,当使用泛型类型作为依赖项时,您可以使用您打算用作泛型参数的类型的知识来执行此操作,并从容器中解析已知类型(在大多数情况下,您可能确切地知道您在寻找什么类型时你实际上使用它)。如果由于没有使用容器或容器容量有限而不是一个选项,并且情况有所不同,并且您要求在编译时知道一个泛型类型参数,那么您可以使用如下方法:

Repository<T> GetRepository<T>()
{
   return Activator.CreateInstance(typeof(Repository<T>));
}

如果它确实是一个不知道的问题,这是一个棘手的问题。我想到的一个想法是拥有一个非通用的Repository类(或者你的类型适合这种模式的任何类),并使具有泛型类子类的子类成为非泛型(但如果方法依赖于泛型类型,它将不起作用) ,他们可能会这样做)并将结果转换为基类非泛型类型。可能很少会出现这种情况。

另一个答案可能是使类非泛型,而只是具有方法的泛型参数。这是我对我的存储库所做的事情,我认为这是一个更好的方法来完成它并简化依赖关系,只需拥有一个存储库类型而不是像持久化类那样的存储库类型。

答案 1 :(得分:1)

我会将所有模型类型存储在同一个存储库中。存储库密钥必须包含模型的类型及其ID。我使用本地类RepositoryKey作为这个purpouse:

public class EditBase
{
    public int ID { get; set; }
    public string Username { get; set; }
    public DateTime CreatedDate { get; set; }
}

public class Repository
{
    private Dictionary<RepositoryKey, EditBase> _store = new Dictionary<RepositoryKey, EditBase>();

    public void Add(EditBase model)
    {
        _store.Add(new RepositoryKey(model), model);
    }

    public void Remove(EditBase model)
    {
        _store.Remove(new RepositoryKey(model));
    }

    public void Remove<T>(int id)
        where T : EditBase
    {
        _store.Remove(new RepositoryKey(typeof(T), id));
    }

    public bool TryGet<T>(int id, out T value)
        where T : EditBase
    {
        EditBase editBase;
        if (!_store.TryGetValue(new RepositoryKey(typeof(T), id), out editBase)) {
            value = null;
            return false;
        }
        value = (T)editBase;
        return true;
    }

    private class RepositoryKey : IEquatable<RepositoryKey>
    {
        private Type _modelType;
        private int _id;

        public RepositoryKey(EditBase model)
        {
            _modelType = model.GetType();
            _id = model.ID;
        }

        public RepositoryKey(Type modelType, int id)
        {
            _modelType = modelType;
            _id = id;
        }

        #region IEquatable<IdentityKey> Members

        public bool Equals(RepositoryKey other)
        {
            if (_modelType != other._modelType) {
                return false;
            }
            return _id == other._id;
        }

        #endregion

        public override int GetHashCode()
        {
            return _modelType.GetHashCode() ^ _id.GetHashCode();
        }
    }
}