Это идеальная книга , которую вы должны прочитать о том, как правильно моделировать ("M" в MVC) репозитории, модели, и он включает в себя прямые ассоциации Linq. В качестве бонуса он решает, как автоматически подключить все ваши пользовательские контроллеры к репозиторию, который они ожидают. Да, он был написан для версии ASP.NET MVC, которая имеет 4 версии (до выпуска), но концепции остаются с вами. Информация относится ко всем проектам MVC (или к любому проекту DDD, а точнее к Linq).
Короче говоря, в книге представлены концепции DDD для внедрения хранилища в ваш пользовательский контроллер.
public class ContentController : Controller
{
IContentRepository _repository;
public ContentController(IContentRepository repo)
{
_repository = repo;
}
public ActionResult Add(Content c)
{
_repository.Add(c);
_repository.SubmitChanges();
return View(c);
}
}
Обратите внимание на используемую здесь концепцию внедрения зависимостей, принудительно вставив хранилище в конструктор. Теперь вы можете просто подключить его самостоятельно без конструктора. Но когда вы попадаете в большой проект (более 50 репозиториев), это помогает использовать инверсию контейнера управления, которая облегчает создание таких объектов для вас, как Castle Windsor (опять же, все в этой книге на 100 страниц выше).
В вашем случае вы просто обращаетесь к объекту User из репозитория пользователя, а затем позволяете остальным выполнить его.
Книга посвящена тому, как моделировать, скажем, ваши сущности «Пользователь» и «Продукт», используя LinqToSql с EntityRef и EntitySet, поэтому все ваши ассоциации будут приняты. Что слишком много кода, чтобы писать здесь. По сути, свяжите объект User () с вашим объектом Product () по идентификатору пользователя и украсьте каждую из этих сущностей атрибутами Linq:
[Table(Name="ut_Content")]
public class Content : EntityBase
{
[Column(IsPrimaryKey = true
, IsDbGenerated = true
, AutoSync = AutoSync.OnInsert)]
public int ContentID { get; set; }
[Column(CanBeNull = false)]
public string ContentKey { get; set; }
[Column(CanBeNull = false)]
public string Title { get; set; }
[Column]
public string Description { get; set; }
[Column]
public string Body { get; set; }
[Column]
public string BodyFormatted { get; set; }
}
Он рассматривает различные варианты использования LinqToSql и показывает, почему здесь работает «Сначала создайте модель, не используйте объекты Linq, сгенерированные схемой».
И, пример репозитория, я думаю, для хорошей меры:
public class ContentRepository : IContentRepository
{
private Table<Content> _contents;
public ContentRepository(string connectionString)
{
DataContext db = new DataContext(connectionString);
_contents = db.GetTable<Content>();
}
public void Add(Content entity)
{
_contents.InsertOnSubmit(entity);
}
}
Помните, одна из лучших особенностей Linq - это функция отложенного выполнения. Вы не работаете над всей таблицей Linq здесь. Ваш запрос откладывается, поэтому вы можете отфильтровать свой IQueryable с помощью Where и Joins и порядков заказов. Только когда вы запрашиваете методы .ToList () или аналогичные, выполняется запрос.
Использование службы DDD
Наконец, для решения вашей первоначальной проблемы «получить пользователя, а затем добавить продукт» в книге игр DDD (Domain Driven Design) есть идеальное решение: Услуги.
Вы бы создали класс UserProductService () в своем Домене, который будет делать именно то, что вы делали выше. Но у него есть преимущество, заключающееся в абстрагировании бизнес-логики в ваш домен, поэтому другие местоположения могут получить доступ и использовать одно и то же бизнес-правило.
public class UserProductService
{
private IProductRepository _productRepository;
private IUserRepository _userRepository;
public UserProductService()
{
// this is where CastleWindsor can really help
_productRepository = new ProductRepository();
_userRepository = new UserRepository();
}
public void AddProduct(int userID, Product product)
{
User user = userRepository.GetUserByID(userID);
// your logic above, abstracted into a service
if (user.IsValid && product.IsValid)
{
product.Owner = user.UserID;
_productRepository.AddProduct(product);
}
}
}
Правило DDD для сервисов таково: если у вас есть два объекта, но вам нужно выполнить общее действие для обоих, используйте сервис для воздействия на оба объекта.