C# N层存储库POCOs-聚合?

C# N层存储库POCOs-聚合?,c#,asp.net,repository-pattern,poco,C#,Asp.net,Repository Pattern,Poco,假设以下简单的POCO、国家和州: public partial class Country { public Country() { States = new List<State>(); } public virtual int CountryId { get; set; } public virtual string Name { get; set; } public virtual string CountryC

假设以下简单的POCO、国家和州:

public partial class Country
{
    public Country()
    {
        States = new List<State>();
    }
    public virtual int CountryId { get; set; }
    public virtual string Name { get; set; }
    public virtual string CountryCode { get; set; }
    public virtual ICollection<State> States { get; set; }
}

public partial class State
{
    public virtual int StateId { get; set; }
    public virtual int CountryId { get; set; }
    public virtual Country Country { get; set; }
    public virtual string Name { get; set; }
    public virtual string Abbreviation { get; set; }
}
当我在UI层中直接使用底层数据提供程序(Entity Framework、NHibernate、PetaPoco等)时,我可以轻松地执行以下操作:

public partial class CountryRepository : IDisposable
{
    protected internal IDatabase _db;

    public CountryRepository()
    {
        _db = new Database(System.Configuration.ConfigurationManager.AppSettings["DbConnName"]);
    }

    public IEnumerable<Country> GetAll()
    {
        return _db.Query<Country>("SELECT * FROM Countries ORDER BY Name", null);
    }

    public Country Get(object id)
    {
        return _db.SingleById(id);
    }

    public void Add(Country c)
    {
        _db.Insert(c);
    }

    /* ...And So On... */
}
public partial class CountryListVM
{
    [Key]
    public int CountryId { get; set; }
    public string Name { get; set; }
    public string CountryCode { get; set; }
    public int StateCount { get; set; }
}
IList<CountryListVM> list = db.Countries
    .OrderBy(c => c.Name)
    .Select(c => new CountryListVM() {
        CountryId = c.CountryId,
        Name = c.Name,
        CountryCode = c.CountryCode,
        StateCount = c.States.Count
    })
    .ToList();
IList list=db.Countries
.OrderBy(c=>c.Name)
.Select(c=>newcountrylistVM(){
CountryId=c.CountryId,
Name=c.Name,
CountryCode=c.CountryCode,
StateCount=c.States.Count
})
.ToList();
但是,当我使用存储库或服务模式时,我会抽象出对数据层的直接访问。我的选择似乎是:

  • 返回包含已填充状态集合的国家,然后在UI层中映射。这种方法的缺点是,我返回的数据比实际需要的要多得多

    -或-

  • 将所有视图模型放入我的公共dll库(而不是将它们放在MVC应用程序的models目录中),并扩展我的存储库以返回特定的视图模型,而不仅仅是域POCO。这种方法的缺点是,我正在将特定于UI的东西(MVC数据验证注释)泄漏到以前干净的POCO中

    -或-

  • 还有其他选择吗

  • 您是如何处理这些类型的事情的?

    其他一些方法:

    • 如果states集合预计不会有太多更改,则可以 允许一点非规范化-将“NumberOfState”属性添加到 国家目标。它将优化查询,但您必须 确保额外字段包含正确的信息

    • 如果您使用的是NHibernate,那么您可以使用ExtraLazyLoading—它会 发出另一个select,但在 叫伯爵。更多信息请点击此处:


    我们的工作实际上取决于项目架构。不过通常。。我们在存储库之上有服务为您处理此逻辑。该服务决定使用哪些存储库来加载哪些数据。流程是UI->Controller->Service->Repositories->DB。UI和/或控制器不了解存储库或其实现


    另外,
    statecont=c.States.Count
    无疑会填充States列表。。不是吗?我敢肯定它会在NHibernate中出现(懒散加载会导致额外的select发送到DB)。

    一个选项是将查询与现有基础结构完全分离。这将是一个设计的实现。在这种情况下,您可以绕过域对象,使用“精简读取层”直接向数据库发出查询。您现有的对象和ORM实际上正在妨碍您,CQRS允许您拥有一个“命令端”,它与您的“查询端”是分开的,可能是一套完全不同的技术,其中每一个都被设计为完成自己的工作,而不会被另一方的需求所影响

    是的,我确实建议不要使用现有的体系结构,或者直接从MVC控制器使用类似的方法(注意未测试的代码示例),例如:

    int count = 
        connection.Query<int>(
            "select count(*) from state where countryid = @countryid", 
            new { countryid = 123 } );
    
    int计数=
    连接.查询(
    “从countryid=@countryid的州中选择计数(*),
    新的{countryid=123});
    
    老实说,你的问题让我思考了好几天。我越来越倾向于认为非规范化是正确的解决方案

    看,领域驱动设计的要点是让问题领域驱动您的建模决策。考虑现实世界中的国家实体。一个国家有一个州的名单。然而,当你想知道某个国家有多少个州时,你并不是在翻阅百科全书中的州列表并数一数。你更可能查看该国的统计数据,并检查那里的州数


    同样的行为也应该反映在你的领域模型中。您可以在country的属性中包含此信息,也可以引入一种CountryStatistics对象。无论你选择什么方法,它都必须是国家总体的一部分。处于聚合的一致性边界将确保它在添加或删除状态时保存一致的数据。

    在第二种方法中,这是否会导致n+1选择(选择以获取国家列表,然后为每个国家选择)?是的,afaik将为每个国家发出计数查询。如果有许多国家,这不是一个好的解决方案。已经有一段时间了,但我认为当我查看StateCount=c.States.Count的跟踪时,它创建了一个聚合,而不是加载集合。我将再次检查,看看情况是否如此。老实说,基础设施还处于起步阶段。我乐于尝试新事物。我试着接受整个n层抽象,但似乎不管我做什么,层之间都有漏洞。今晚晚些时候我会看CQRS的资料。我现在正在玩的ORM是NPoco(PetaPoco的分支)。它类似于短小精悍,非常灵活。阻碍进展的是存储库模式的想法,以及为可测试性而采取的一切措施。除了最简单的例子之外,这是一个主要的PITA。如果您通过定义聚合边界将DDD样式应用于域对象持久性,并确保您的存储库契约只允许Get(id)和Add(object),并将任何和所有查询留给一个完全独立的垂直切片(有自己的图层,但可能只有一两层,而不是典型的数量)那么你应该是金色的。