从联接表上的存储库返回域对象 [英] Returning Domain Objects from Repositories on Joining tables

查看:78
本文介绍了从联接表上的存储库返回域对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在阅读存储库应仅返回域对象。我很难实现这一点。我目前拥有带有服务层,存储库的API,并且正在使用EF Core访问sql数据库。

I have been reading that Repositories should return domain objects only. I am having difficulty with implementing this. I currently have API with Service Layer, Repository and I am using EF Core to access sql database.

如果我们将User(Id,姓名,地址,电话号码,电子邮件,用户名)和订单(id,OrderDetails,UserId)视为2个域对象。一个客户可以有多个订单。我已创建导航属性

If we consider User(Id, Name, address, PhoneNumber, Email, Username) and Orders (id, OrderDetails, UserId) as 2 domain objects. One Customer can have multiple Orders. I have created navigation property

public virtual User User{ get; set; }

和外键。

服务层需要返回DTO,其中包含OrderId,OrderDetails,CustomerId,CustomerName。在这种情况下,存储库应该返回什么?这就是我正在尝试的:

Service layer needs to return DTO with OrderId, OrderDetails, CustomerId, CustomerName. What should the Repository return in this case? This is what i was trying:

public IEnumerable<Orders> GetOrders(int orderId)
        {
            var result = _context.Orders.Where(or=>or.Id=orderId)
                .Include(u => u.User)
                .ToList();
            return result;
        }

我在急切加载时遇到了麻烦。我试图使用包含。我首先使用数据库。在上述情况下,导航属性始终使用NULL进行调整。我能够将数据获取到Navigation Properties中的唯一方法是启用上下文的代理的延迟加载。我认为这将是性能问题

I am having trouble with Eager loading. I have tried to use include. I am using Database first. In the case of above, Navigation Properties are always retuned with NULL. The only way i was able to get data in to Navigation Properties was to enable lazy loading with proxies for the context. I think this will be a performance issue

任何人都可以帮助我返回什么,为什么.include无法正常工作?

Can anyone help with what i should return and why .Include is not working?

推荐答案

存储库可以返回其他类型的对象,即使原始类型(如整数)也可以返回,如果您想基于

Repositories can return other types of objects, even primitive types like integers if you want to count some number of objects based on a criteria.

这是来自域驱动设计书:

This is from the Domain Driven Design book:


他们(存储库)还可以返回符号信息,例如(域对象的)多少实例满足某些条件的
计数。
他们甚至可以返回汇总计算,例如
中所有具有某些数字属性的匹配对象的总数。

They (Repositories) can also return symmary information, such as a count of how many instances (of Domain Object) meet some criteria. They can even return summary calculations, such as the total across all matching objects of some numerical attribute.

如果您返回的东西不是域对象,那是因为您需要有关域对象的一些信息,因此您只应返回不可变的对象和原始数据类型,例如整数。

If you return somethings that isn't a Domain Objects, it's because you need some information about the Domain Objects, so you should only return immutable objects and primitive data types like integers.

如果您查询要获取的对象,并且想要在获取后对其进行更改,那么它应该是域对象。

If you make a query to get and objects with the intention of changing it after you get it, it should be a Domain Object.

如果需要这样做

这是一篇很好的文章,解释了如何将模型分解为聚合:> https://dddcommunity.org/library/vernon_2011/

Here's a good article that explains how to decompose your model into aggregates: https://dddcommunity.org/library/vernon_2011/

在您的这种情况下,您可以将User和Order实体组合为一个Aggreate,也可以将它们分为单独的聚合

In your case you can either compose the User and the Order entities in a single Aggreate or have them in separate Aggregates.

编辑:

示例:

在这里,我们将使用按ID引用,来自不同集合的所有实体都将按ID引用来自不同集合的其他实体。

Here we will use Reference By Id and all Entities from different Aggregates will reference other entities from different Aggregates by Id.

我们将拥有三个聚合用户产品订单以及一个 ValueObject OrderLineItem

We will have three Aggregates: User, Product and Order with one ValueObject OrderLineItem.

public class User {

    public Guid Id{ get; private set; }
    public string FirstName { get; private set; }
    public string LastName { get; private set; }
}

public class Product {

    public Guid Id { get; private set; }
    public string Name { get; private set; }
    public Money Price { get; private set; }
}

public class OrderLineItem {

    public Guid ProductId { get; private set; }
    public Quantity Quantity { get; private set; }
    // Copy the current price of the product here so future changes don't affect old orders
    public Money Price { get; private set; } 
}

public class Order {

    public Guid Id { get; private set; }
    public IEnumerable<OrderLineItem> LineItems { get; private set; }
}

现在,如果您必须在自己的数据库中进行大量查询应用程序,您可以创建一个 ReadModel ,该模型将根据上面的模型创建

Now if you do have to do heavy querying in your app you can create a ReadModel that will be created from the model above


public class OrderLineItemWithProductDetails {

    public Guid ProductId { get; private set; }
    public string ProductName { get; private set; }

    // other stuff quantity, price etc.
}

public class OrderWithUserDetails {

    public Guid Id { get; private set; }
    public string UserFirstName { get; private set; }
    public string UserLastName { get; private set; }
    public IEnumerable<OrderLineItemWithProductDetails > LineItems { get; private set; }
    // other stuff you will need

}

如何填充ReadModel是一个完整的主题,所以我无法涵盖全部内容,但是这里有一些提示。

How you fill the ReadModel is a whole topic, so I can't cover all of it, but here are some pointers.

您说过会做一个Join,因此您可能正在使用某种类型的RDBMS,例如PosteSQL或MySQL。您可以在特殊的ReadModel 存储库中进行加入。如果您的数据位于单个数据库中,则可以使用ReadModel存储库。

You said you will do a Join, so you're probably using RDBMS of some kind like PosteSQL or MySQL. You can do the Join in a special ReadModel Repository. If your data is in a single Database, you can just use a ReadModel Repository.


// SQL Repository, No ORM here
public class OrderReadModelRepository {

    public OrderWithUserDetails FindForUser(Guid userId) {

        // this is suppose to be an example, my SQL is a bit rusty so...
        string sql = @"SELECT * FROM orders AS o 
                    JOIN orderlineitems AS l
                    JOIN users AS u ON o.UserId = u.Id
                    JOIN products AS p ON p.id = l.ProductId
                    WHERE u.Id = userId";

        var resultSet = DB.Execute(sql);

        return CreateOrderWithDetailsFromResultSet(resultSet);
    }
}

// ORM based repository
public class OrderReadModelRepository {

    public IEnumerable<OrderWithUserDetails> FindForUser(Guid userId) {

        return ctx.Orders.Where(o => o.UserId == userId)
                         .Include("OrderLineItems")
                         .Include("Products")
                         .ToList();
    }
}

如果不是,那么您会必须将其构建并保存在单独的数据库中。您可以使用 DomainEvents 来做到这一点,但是如果您只有一个SQL,我不会走那么远数据库。

If it's not, well you will have to build it an keep it in a separate database. You can use DomainEvents to do that, but I wont go that far if you have a single SQL database.

这篇关于从联接表上的存储库返回域对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆