Linq to sql Repository模式,有些问题

时间:2010-04-09 19:37:57

标签: c# linq-to-sql design-patterns

我使用linq到sql的存储库模式,我每个表使用一个存储库类。 我想知道,我是以良好/标准的方式做事,

ContactRepository

  Contact GetByID()
  Contact GetAll()

COntactTagRepository

 List<ContactTag> Get(long contactID)
 List<ContactTag> GetAll()
 List<ContactTagDetail> GetAllDetails()

class ContactTagDetail
{
  public Contact Contact {get;set;}
  public ContactTag COntactTag {get;set;}
}

当我在contactrepository中需要联系方式i调用方法时,对于contacttag

也是如此

但是当我需要联系和标签在一起时我在ContactTag存储库中调用GetDetais()它没有返回由orm生成的COntactTag实体,它返回的ContactTagDetail实体同时包含orm生成的COntact和COntactTag,我知道我可以简单地调用GetAll在COntactTag存储库中并且可以访问Contact.ContactTag但是作为它的linq到sql它将在查询级别没有延迟加载的选项,所以每当我需要一个具有相关实体的实体时我创建一个投影类

另一个疑问是,我真的需要正确的方法,我可以在联系人和&amp; ContactTag repostitory就像在联系人库GetALlWithTags()或其他东西,但我在COntactTag存储库中做它

你的建议是什么?

3 个答案:

答案 0 :(得分:5)

我没有时间详细介绍,但基本上没有表与您的存储库之间的一对一关系。我犯了这个错误,但它不起作用。相反,让您的存储库包含所有与概念相关的表。在您的情况下,只需要一个联系人存储库来处理Contacts和ContactTag(以及任何其他相关表)。没有关于“相关”意味着什么的规则,只有你可以决定 - 但是根据你对应用程序元素如何自然地组合在一起的理解来管理你的决定。

还要读取SO上的这两个线程来处理类似的问题:

Multiple or Single Repositories with LINQHow to use the repository pattern correctly?

答案 1 :(得分:1)

这不是存储库模式。存储库模式基本上是通过(在概念上)作为域中某种类型的所有对象的集合来创建一个抽象持久性的对象。

因此,联系人存储库可能会这样:

IContacts contacts = GetContactRepository();
using(var uow = UnitOfWork.Create()) {
  var contact1 = contacts.Get(new FindByNameSpecification("Fred"));
  contact1.LastName = "Rubble";
  var contact2 = new Contact("Barney", "Flistone");
  contacts.Add(contact2);
  // both contact1 and contact 2 are implicitly saved at the end of the unit of work
}  

关于存储库应该如何工作的略微宽松的定义可能是这样的:

IContactRepository contacts = GetContactRepository();
using(var uow = UnitOfWork.Create()) {
  var contact1 = contacts.GetByName("Fred");
  contact1.LastName = "Rubble";
  contacts.Save(contact1);
  var contact2 = new Contact("Barney", "Flistone");
  contacts.Save(contact2);
}  //The save is explicit but the commit is implicit

你得到的是table data gateway

问题是您要为每个表创建一个网关。我建议反对。

是否标记了您的联系人域名的一部分?如果是,那么你应该有属性

public class Contact {
  public IEnumerable<Tag> Tags { get; }
  public void TagWith(Tag tag) { .... }
  public void UnTag(Tag tag) { ... }
}

另外,问问自己,你是否会在其下添加一个零联系的标签?如果不是那么它变得更容易 - 你根本不需要网关来管理标签,只需让你的Contact对象处理它

public interface IContactRepository {
  IEnumerable<Contact> GetAll(); // returns Contacts along with their tags
  void Save(Contact); // saves Contact along with any tags
} 

顺便说一句,如果标记不是您域的一部分(因为它是一个应用程序问题),那么您应该有一个单独的服务,甚至可能在一个单独的项目中

public interface IAssociateTags {
  IEnumerable<Tag> GetTagFor(Contact contact);
  void TagContact(Contact contact, Tag tag);
  void UnTagContact(Contact contact, Tag tag);
}

答案 2 :(得分:-1)

我相信你走的正确。 你将遇到linq to sql的一个问题是与表的一对一映射。因此,您不得不向您公开多对多的关系表。

我解决这个问题的方法是使用一个可以访问linq到sql的数据层,但在返回调用之前将所有内容映射回POCO对象。

 public IQueryable<ArtGalleryData.Image> GetImagesByImageGroup(int id)
    {

        return SqlDataContext.Image_ImageGroups
            .Where(iig => iig.ImageGroupID == id)
            .Join(
            SqlDataContext.Images,
            iig => iig.ImageID,
            i => i.ImageID,
            (iig, i) => new ArtGalleryData.Image 
            { ImageID = i.ImageID, 
              Description = i.Description, 
              Title = i.Title, 
              Height = i.Height, 
              Width = i.Width }).AsQueryable();
    }

基本上我将linq对象Image映射回POCO对象Image。 (我知道它有点乱,但它是我手头上最好的例子。)

要获得延迟加载的效果,您将返回IQueryable&lt; T&gt;宾语。这将允许您在需要之前暂停执行查询。

对于具有依赖集合的对象,我发现了这个很棒的帮助器类:LazyList它允许通过IQueryable&lt; T&gt;

进行集合的延迟加载(延迟执行)

我所知道的大多数内容来自于阅读Rob Connerys博客MVC Store Front

阅读他的博客文章并下载Store front项目我认为它将回答您的许多问题。如果你不使用asp.net MVC只是查看他的数据访问层应该是一个巨大的帮助。

希望有所帮助