Шаблон стратегии для экземпляра Различные репозитории на основе переменной типа - PullRequest
2 голосов
/ 29 ноября 2011

Я работаю над вики-проектом.Код 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 ]

1 голос
/ 07 декабря 2011

Я бы сохранил все типы моделей в одном и том же хранилище. Ключ хранилища должен содержать тип модели и ее идентификатор. Я использую местный класс 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();
        }
    }
}
1 голос
/ 02 декабря 2011

Я не совсем уверен, что понимаю, что вам нужно, но я считаю, что вопрос заключается в том, как взять открытый универсальный тип и сделать его закрытым универсальным типом.

, если это так, попробуйте этомагия отражения:

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

или, если вы используете контейнер или что-то в этих строках, разрешите получившийся закрытый универсальный тип из вызова MakeGenericType из контейнера, а не с помощью Activator.CreateInstance.в любом случае, вам следует получить экземпляр того, что вы хотите.

это то, что вы ищете?

РЕДАКТИРОВАТЬ: в ответ на вопрос Оливье Жако:Descombes, вот некоторые мысли и код:

в идеале, я бы использовал некоторые встроенные возможности вашего ioc-контейнера по выбору или что-то вроде этого кода отражения, чтобы зарегистрировать открытый универсальный тип с контейнером или чем-то еще.выберите закрытые типы (возможности контейнеров различаются).затем при использовании универсального типа в качестве зависимости вы можете сделать это, зная тип, который вы намереваетесь использовать в качестве универсального параметра, и разрешить известный тип из контейнера (в большинстве случаев вы точно знаете, какой тип вы ищете, когдаВы действительно используете это).если это не вариант из-за неиспользования контейнера или его ограниченных возможностей, а ситуация немного отличается, и вы запрашиваете параметр общего типа, который вы знаете во время компиляции, у вас может быть метод, похожий на этот:

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

Если это действительно такая ситуация, как вопрос, где это неизвестно, то это сложный вопрос.одна мысль, которая приходит на ум, - это иметь неуниверсальный класс репозитория (или любой другой тип, который подходит этому шаблону) и сделать класс с подклассом универсального типа неуниверсальным (но он не будет работать, если методы зависят от универсального типа, что они, вероятно, и делают) и приводят результат к базовому, неуниверсальному типу.возможно, очень мало ситуаций, когда это действительно сработало бы.

другой ответ может заключаться в том, чтобы сделать класс неуниверсальным и вместо этого просто иметь общие параметры для методов.это то, что я сделал с моими репозиториями, и я думаю, что в любом случае это лучший способ сделать это и упростить зависимости, имея только один тип репозитория вместо столько типов репозиториев, сколько у вас есть постоянные классы.

...