LINQ,存储库模式和数据库抽象

时间:2009-06-26 15:45:46

标签: asp.net-mvc linq repository-pattern

我现在花了一些时间来解决迄今为止我没有解决方案的问题。我有一个预定义的非常庞大的数据库,其结构是固定的。我使用存储库模式在服务代码和数据库逻辑之间创建一个抽象层。问题是,我需要在将数据库对象传递出存储库之前对数据库对象应用一些处理。因此,我无法直接使用Linq实体。

基本上,存储库方法如下所示:

public IList<Bookingcode> FindBookingcode(int id) {
   return (from b in _db.BOOKINGCODE
           where b.ID == id
           select new Bookingcode {
              Id = b.ID,
              Name = b.NAME.Trim()
           }).ToList();
}

到目前为止效果很好。但我有很多应该单独组成的对象。 FindBookingcode()应该返回一个几乎完整的对象与其他对象,如目录等。我现在的问题是我必须像这个例子那样多次重写映射:

public IList<Bookingcode> FindBookingcode(int id) {
    return (from b in _db.BOOKINGCODE
            join c1 in _db.CATALOG on b.CATALOGID equals c1.ID
            where b.ID == id
            let refs = (
                from bc1 in _db.BOOKINGCODE
                join p in _db.PACKAGE on bc1.ID equals p.BOOKINGCODE
                join bc2 in _db.BOOKINGCODE on p.PACKAGEREF equals bc2.ID
                join c in _db.CATALOG on bc.CATALOGID on bc2.CATALOGID equals c.ID
                where bc1.ID == b.ID
                select new PackageInfo {
                   ID = p.ID
                   BookingcodeRef = new Bookingcode { 
                       ID = bc2.ID,
                       Catalog = new Catalog { ID = c.ID }
                   }
                })
            select new Bookingcode {
              ID = b.ID,
              PackageInfo = refs.ToList()
            }).ToList();

}

我在存储库中也有一些L2O处理,它组装了返回的对象。另一件我没有很酷解决方案的方法是告诉存储库它应该获取什么,比如FindBookingcode(id,includePackageInfo,includeCatalog)。

以下是问题:

1)这种做法完全是愚蠢的吗?

2)你能指导我一个使重映射更简单的解决方案吗?

3)如何实施DDD的标准机制

4 个答案:

答案 0 :(得分:3)

在我的存储库中,我有一个单独的构建方法,它接受一个LINQ to SQL实体并返回一个业务对象。

构建方法看起来像(this.Container是一个Unity IoC容器,对于该示例并不重要):

private IGroup BuildGroup(Entities.Group group)
{
    IGroup result = this.Container.Resolve<IGroup>();
    result.ID = group.GroupID;
    result.Name = group.Name;

    return result;
}

然后每个方法使用构建方法返回业务对象:

public override IGroup GetByID(int id)
{
    try
    {
        return (from g in this.Context.Groups
                where g.GroupID == id && g.ActiveFlag
                select this.BuildGroup(g)).Single();
    }
    catch (InvalidOperationException)
    {
        return null;
    }
}

这可以通过从数据库中获取每个LINQ to SQL实体并通过构建方法运行它来工作,因此在这种情况下,您的结果将是业务对象的可枚举,而不是LINQ to SQL实体。

答案 1 :(得分:1)

您使用的是Linq to SQL还是Entity Framework?

我假设您正在使用实体框架,因为您在问题中提到了“LINQ实体”。

您应该能够使用Entity Framework 导航进行此类映射 性能即可。您需要将导航属性添加到您希望以这种方式映射的每个实体。它就像告诉视觉设计师哪个属性映射到另一个实体中的相应属性一样简单。

查看How do I Entity Framework video series以获取快速入门指南。我建议观看整个系列,因为它们非常有用。

答案 2 :(得分:1)

如果我调用类似的存储库方法

var list = x.FindBookingcode(int id)
我希望能够将项目添加到列表中,而不用担心它将如何持久保存到数据库中。在示例实现中,您的存储库功能无法检测到有人在列表中添加了某些内容,因此无法对其执行任何操作。

我也希望能够通过规范。规范基本上是作用于您的存储库类型的委托,返回一个布尔值来指示是否必须考虑它。通常,您将实现一个实现逻辑和/或非运算符的基本规范,以便您可以轻松地将规范组合成新的规范。

答案 3 :(得分:0)

首先 - 长时间回答我的回答^^我很忙,以至于我忘了回答。

John,你的解决方案非常适合解决我的多重映射问题。

DoctaJonez,我正在使用Linq2SQL。我已经使用Entity Framework进行了一些测试,但也使用了NHibernate。映射问题的根源是,我有一个给定的数据库模式,有时真的很难看。所以我在访问数据时要做很多处理。 NHibernate工作得很好,我想我会在不久的将来将它添加到项目中。

汉斯,你的观点是对的。但是因为项目只是数据库的查询API,所以没有对数据库的写入。它更像是一个服务的DLL,其他应用程序使用它来从我公司使用的预订软件中获取信息。

您已经提到过“规格”,这也是一个很好的观点。因为我有很多过滤器的巨大搜索查询,我真的需要一个良好的api存储库。这样的问题是,例如,滤波器的不同组合也启动不同的处理逻辑。这也应该创建不同的SQL才能生效。

因为我已经映射了对象并使用Linq到SQL,所以我无法使规范像他们应该的那样工作。所以我在存储库中有很多方法来获取具有不同crierias的对象,如下所示:

Bookingcode FindBookingcode(int id);
Bookingcode FindBookingcode(string code, string catalog);
List<Bookingcode> FindBookingcode();
List<Bookingcode> FindBookingcode(int[] ids);
List<Bookingcode> FindBookingcode(string code);
List<Bookingcode> FindBookingcode(string[] codes);
List<Bookingcode> FindBookingcodes(Catalog catalog);

因为我不使用IQueryable我不能链接像

这样的东西
repo.GetBookingcodes().WithCatalog("WI09").WithCode("XYZ10001");

对于像Searches这样的大型界面,我使用像这样的过滤器对象

srv.SearchTransactions(new TransactionSearchFilter { 
    Customer = 1234, Destination = "DXB", ExtractServices = true });

然后,存储库有一些逻辑可以将数据从数据库中取出。在存储库中进行测试以获得像这样的工作

    repo.QueryTransactions()
    .Include<Customer>()
    .Include<TransactionsService>()
    .FilterBy(TransactionSearchFilter.Customer, 1234)
    .FilterBy(TransactionSearchFilter.Destination, "DXB")
    .Execute();

在内部构建一个标准/规范。但这看起来真的像Entity Framework,也许如果我更深入,我可以使用它或NHibernate。

我的存储库中最有问题的部分是搜索,因为需要在性能方面创建某种动态SQL。我已经使用了PredicateBuilder,但如果设置了特定的过滤器,我无法解决一些更改/包含表连接的查询。

我想我必须'扫描'更多文档。谢谢你的回复。