2017-02-22 35 views
0

Я признаю, что большая часть моей проблемы с этим должна быть связана с простым непониманием вокруг нескольких компонентов, участвующих в решении. Я не совсем «новичок» в Entity Framework, кодовых и не общих типах, но внутренняя работа всех трех до сих пор достаточно таинственна для меня, что это дает мне возможность.Универсальный метод добавления в инфраструктуре сущностей - проблема с переходом типа из строкового имени

У меня есть код-первый проект, в котором я выделил классы «модели» из классов «обслуживания», с обобщениями в обоих. Я NOT с использованием всего Образцовый шаблон по разным причинам. Для большей части того, что я делаю, структура, которую я нахожу, прекрасно работает - я понимаю это, и это кажется совершенно чистым.

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

(Фон: Мне нужно сделать это, потому что я «семя» нескольких таблиц в базе данных с значениями инициализации из файла JSON. Этот JSON-файл содержит имена модельных сущностей. Поэтому во время выполнения мне нужно . получить это значение строки, а затем кормить, что в качестве типа к родовому объекту сервиса, который делает операции базы данных)

Вот соответствующие фрагменты кода:

В BaseEntity.cs у меня есть верх -уровень интерфейса и ряд абстрактных классов, из которых затем наследуются конкретные объекты модели:

namespace POST.API.Models 
{ 
    public interface IEntity 
    { 
     int Id { get; set; } 
    } 

    public abstract class BaseEntity { } 

    public abstract class Entity : BaseEntity, IEntity 
    { 
     public virtual int Id { get; set; } 
    } 

    public abstract class TypeEntity : Entity 
    { 
     public TypeDefinition Definition { get; set; } 
    } 
} 

В BaseService.cs У меня есть другой интерфейс и более абстрактные классы, из которых специфические классы модели обслуживания унаследовать. Существует также один конкретный класс, вот, что обобщается для выполнения операции вставки:

namespace POST.API.Services 
{ 
    public interface IEntityService { } 

    public abstract class BaseEntityService<T> : IEntityService 
     where T : Models.BaseEntity 
    { 
     public T Fetch(int Id) 
     { 
      using (var Db = new PostDbContext()) 
      { 
       return Db.Set<T>().Find(Id); 
      } 
     } 

     public void Create(T Item) 
     { 
      if (Item != null) 
      { 
       using (var Db = new PostDbContext()) 
       { 
        DbSet Entity = Db.Set<T>(); 

        Entity.Add(Item); 
        Db.SaveChanges(); 
       } 
      } 
     } 

     public IEnumerable<T> All() 
     { 
      using (var Db = new PostDbContext()) 
      { 
       return (IEnumerable<T>)Db.Set<T>().ToList(); 
      } 
     } 
    } 

    public abstract class BaseTypeEntityService<T> : BaseEntityService<T> 
     where T : Models.TypeEntity 
    { } 

    public abstract class BasePropertyTypeEntityService<T> : BaseTypeEntityService<T> 
     where T : Models.PropertyTypeEntity { } 

    public abstract class BasePropertyEntityService<T> : BaseEntityService<T> 
     where T : Models.BaseEntity { } 

    public class TypeEntityService<T> : BaseTypeEntityService<T> 
     where T : Models.TypeEntity { } 

    #endregion 
} 

Я удалил некоторые методы не подходящие для презентации.

У меня есть некоторый код, который затем пытается использовать эти базовые классы рыться файла JSON и вставить несколько строк, таким образом:

 using (PostDbContext Db = new PostDbContext()) 
     { 
      string JsonString = System.IO.File.ReadAllText(JsonDataFile); 
      DataSet JsonDataSet = JsonConvert.DeserializeObject<DataSet>(JsonString); 
      foreach (DataTable Table in JsonDataSet.Tables) 
      { 
       Type EType = Type.GetType("POST.API.Models." + Table.TableName); 
       POST.API.Models.BaseEntity E = (POST.API.Models.BaseEntity)Activator.CreateInstance(EType); 
       Services.TypeEntityService<EType> S = new Services.TypeEntityService<EType>(); 

       foreach (DataRow Row in Table.Rows) 
       { 
        // Set properties of E and call Create method of S 
       } 
      } 
     } 

Я явно неправильно понял что-то фундаментальное, потому что код не будет компиляции. На этой строке кода:

Services.TypeEntityService<EType> S = new Services.TypeEntityService<EType>(); 

... Я получаю ошибку на мои ссылки на ETYPE, с компилятором жалуясь «Тип или пространство имен` EType»не может быть найден.»

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

ответ

1

Вам необходимо создать Services.TypeEntityService<EType> с активатором, что-то вроде ниже ...

  Type EType = Type.GetType("POST.API.Models." + Table.TableName); 
      Type[] typeArgs = { EType }; 
      var generic = typeof(Services.TypeEntityService<>).MakeGenericType(typeArgs); 
      var S = Activator.CreateInstance(generic); 
+0

Хорошо. Это имеет смысл для меня в некоторых отношениях и действительно решает одну проблему. Однако я все еще не могу ссылаться на свойства и методы переменных E и S, что является целым ... То есть я не могу фактически установить свойства E, а затем вызвать метод Create для S, чтобы добавить новый E ... –

+0

Я не включил код для создания E, но оттуда вам нужно будет использовать отражение для вызова метода из 'var method = S.GetMethod (« MyMethodName »);' и затем 'var result = method .Invoke (generic, new object [] {E}); ' –

+0

За исключением того, что S не имеет доступного метода GetMethod, по крайней мере, так, как код присутствует в структуре ... S имеет только равные, GetType, GetHashCode и ToString , как var ... –

1

Ну у вас есть variabl типа System.Type в EType. Вы не можете использовать экземпляры Type для общих типов. Вы должны изменить свою реализацию Services.TypeEntityService на использование экземпляров экземпляра времени выполнения (например, TypeEntityService (тип System.Type)).

Редактировать: Или, как и другие состояния ответа, используйте Reflection для создания общих параметров из экземпляра Type. Это имеет больше смысла.