Концептуальные трудности 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
поле