何时公开 IEnumerable 而不是 ICollection?

When to expose an IEnumerable instead of an ICollection?

public class Order
{
 public int Id {get;set;}
 [DisplayName("User")]
 public long UserId { get; set; }
 [ForeignKey("UserId")]
 public virtual User User { get; set; }
 public decimal Amount { get; set; }
}

IEnumurable

public class User
{
 public int Id{get;set;}
 public virtual IEnumerable<Order> Orders { get; set; } 
}

public User GetWithOrders()
{
 var myUser=UserRepository.GetByEmail("email@email.com");
 myUser.Orders=OrderRepository.GetByUserId(myUser.Id);
 return myUser;
}

ICollection

public class User
{
 public int Id{get;set;}
 public virtual ICollection<Order> Orders { get; set; } 
}

public User GetWithOrders()
{
 var myUser=UserRepository.GetByEmail("email@email.com");
 return myUser;
}

我没有使用 IEnumerable 进行导航 属性 的延迟加载。因此,我必须通过另一个查询来获取该用户的订单。

我有 ICollection 的导航。这样我就可以收到用户的订单。这看起来很酷。但是我可以在不使用服务或存储库的情况下向控制器中的用户添加新订单。

它是一种在控制器级别上操作数据。这是反模式吗?

这里没有真正的选择。 EF 需要 ICollection 来控制它的某些方面,例如绑定查询结果和延迟加载。通过使用 IEnumerable,您实际上关闭了所有这些功能,但同时关闭了 EF 对您的底层结构的理解。当您生成迁移时,EF 不会为 M2M 关系、相关表上的外键等生成任何必要的基础连接表。

多空,用ICollection。虽然您是正确的,这允许您通过简单地将项目添加到相关实体 sans-DAL 的集合中来添加项目,但如果不访问上下文,它们仍然无法 saved .如果您已正确设置 DAL,则只能通过 DAL 本身使用,因此您仍然必须将实体传回 DAL 管道以延续任何这些更改。换句话说,不用担心。

But [with ICollection] I can add new order in Controller without using service or repository.

你的意思是你可以这样做(假设有一个用于向用户添加订单的视图模型和一个 SaveChanges() 某处):

public class UserController
{
    public ActionResult AddUserOrder(AddUserOrderModel addOrder)
    {
        User user = User.GetByEmail(addOrder.UserEmail);        
        user.Orders.Add(addOrder.Order);
        User.SaveChanges();
    }
}

尤其是您可以 user.Orders.Add(...),这是从您的服务或存储库层公开实体类型的副作用。

如果您想避免这种情况,您必须定义并公开一个业务对象,其中包含您要公开的成员:

public class UserBLL
{
    public int Id { get; private set; }
    public IEnumerable<Order> Orders { get { return _orders.AsEnumerable(); } }
    private IEnumerable<Order> _orders;

    public UserBLL(User user)
    {
        Id = user.Id;
        _orders = user.Orders;          
    }

    public void AddOrder(Order order)
    {
        _orders.Add(order);
    }
}