Концептуальные трудности Entity Framework и Repository Pattern

Я делаю сайт для внутренней сети с использованием ASP.NET MVC и SQL Server 2012. Я делаю хранилище и архитектуру с помощью Onion Architecture. Моя проблема в том, что компания, в которой я работаю, уже имеет несколько серверных БД, в которых таблицы не имеют никаких отношений между собой. Вместо этого есть таблицы для сопоставления этих отношений. Например, таблица User и таблица Document имеют таблицу User_joint_Document для создания отношения, содержащую оба идентификатора (IDDocument и IDUser). Теперь, когда я пишу свой общий репозиторий:

class Repository<T> : IRepository<T> where T : class 

проблема в том, что универсальный тип T не имеет смысла, и я не могу повлиять на значения в моей модели с помощью запросов EF, что является нормальным, и что было бы здорово, если бы у родительского класса BaseEntity были идентификаторы, определенные для каждой таблицы, тогда я могу написать:

class Repository<T> : IRepository<T> where T : BaseEntity

И все мои модели таблиц будут наследоваться от BaseEntity. Но это также означало бы переписывание всей БД реляционным способом и сопоставление каждой POCO БД вручную (исправьте меня, если я ошибаюсь), и у меня нет навыков для этого (в разных серверных БД более 300 таблиц) и мне не хватает надлежащих знаний и опыта для проведения подобного рода операций).

Есть ли способ сохранить исходную структуру БД и написать общий репозиторий? Как можно это сделать?

РЕДАКТИРОВАТЬ Чтобы уточнить мой вопрос, потому что @saeb частично ответил на мой вопрос. Могу ли я иметь общий репо без родительского класса для моих POCO БД? Или мне это нужно для того, чтобы потом иметь только ОДИН репозиторий, чтобы управлять ими всеми? Например:

class Repository<T>:IRepository<T> where T : class
{
  private readonly ApplicationContext context;
  private DbSet<T> entities;
  public Repository(PrincipalServerContext context)
  {
        this.context = context;
        entities = context.Set<T>();
  }
  public T Get(long id)
  {
     return entities.SingleOrDefault(s => s.IDUser == id);
     //This does not work, IDUser isn't recognized

  }

Спасибо за вашу помощь!

2 ответа

Решение

... имеет несколько серверных БД, в которых таблицы не связаны между собой...

Но у них есть отношение, отношение " многие ко многим", которое определяется с помощью этой третьей таблицы сопоставления (является ли это правильно определенным отношением, это другая тема)

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

Почему нет, а почему нет? учитывая ваши примеры таблиц, у вас будет две сущности, User а также Document и они будут выглядеть так:

public class User
{
    public int IDUser { get; set; }

    public virtual ICollection<Document> Documents { get; set; }

    ...
}

public class Document
{
    public int IDDocument { get; set; }

    public virtual ICollection<User> Users { get; set; }

    ...
}

И вы можете использовать свободный API в вашем контексте OnModelCreating установить отношения через третью таблицу:

public class YourContext: DbContext
{
    ...

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>()
            .HasMany<Document>(u => u.Documents)
            .WithMany(d => d.Users)
            .Map(userJointDocument =>
                {
                    userJointDocument.MapLeftKey("IDUser");
                    userJointDocument.MapRightKey("IDDocument");
                    userJointDocument.ToTable("User_joint_Document");
                });
    }

    ...
}

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

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

Вы можете поиграть с выражениями для достижения общего репозитория

public interface IEntity<T> where T : class
{
    Expression<Func<T, bool>> GetByIdPredicate(long id);
}        

public partial class User : IEntity<User>
{
   public int UserID { get; set; }

   public Expression<Func<User, bool>> GetByIdPredicate(long id)
   {
      return (User entity) => entity.UserID == id;
   }
}

class Repository<T>:IRepository<T> where T : class, IEntity, new()
{
  private readonly ApplicationContext context;
  private DbSet<T> entities;
  T dummyEntity;

  public Repository(PrincipalServerContext context)
  {
        this.context = context;
        entities = context.Set<T>();
        dummyEntity = new T();
  }
  public T Get(long id)
  {
     return entities.SingleOrDefault(dummyEntity.GetByIdPredicate(id));
  }

Там, вероятно, более чистый способ, который также избавляет от dummyEntity поле

Другие вопросы по тегам