创建使用域实体的可重用类

时间:2013-05-12 17:51:42

标签: c# .net asp.net-mvc entity-framework

作为开发人员,我正在尝试使我的类更加模块化和可重用。我遇到问题的一个领域是我设计一个类来处理实体框架实体。

例如,我可能会创建一个购物车类,其角色是充当产品,折扣和其他与结帐相关的容器。它公开了获取购物车总数的方法,并实施了一些与购物车能够和不能做的相关的业务规则。

我可能创建和实体框架实体是“产品”并让我的购物车接受这个实体。这看起来很方便,它会在我正在使用购物车的项目中对Product类产生不必要的依赖。如果我想将该购物车重新用于另一个项目,那么“Product”实体不一定是一样的。

如何以一种不会导致架构问题的方式优雅地将我的购物车类与实体框架分离?

我想过创建一个接口IProduct,它具有购物卡所需的相关属性和方法,然后使我的实体类成为IProduct的一个实例。

基本上,我正在寻找一个好的设计模式来将我的类与项目的本地域实体分离,无论它们采取何种形式......

这就是我最终的目标;通用购物车,其中T是IProduct。然后,我将我的实体框架实体设为IProduct:

public interface IProduct
{
    /// <summary>
    /// Unique Identifier For the product.
    /// </summary>
    int Id { get; set; }
    decimal Price { get; set; }
}

public interface IShoppingCart<T> where T : IProduct
{
    /// <summary>
    /// Returns the total of all the products without any modifiers.
    /// </summary>
    decimal SubTotal { get; }

    /// <summary>
    /// Returns a total of everything in the cart, including all applicable promotions.
    /// </summary>
    decimal Total { get; }

    /// <summary>
    /// Returns a total of the discounts for the applicable promotions in the cart.
    /// </summary>
    decimal TotalDiscount { get; }

    /// <summary>
    /// Returns a count of products in the cart.
    /// </summary>
    int ProductCount { get; }

    /// <summary>
    /// Returns a count of unique products in the cart.
    /// </summary>
    int UniqueProductCount { get; }

    /// <summary>
    /// Adds a product increasing the product count if there is already one in the cart.
    /// </summary>
    /// <param name="product">Product To Add</param>
    void AddProduct(T product);

    /// <summary>
    /// Remove an instance of a product from the cart, return the product that was removed.
    /// </summary>
    /// <param name="id"></param>
    /// <returns>Instance of T</returns>
    void RemoveProduct(int id);

    /// <summary>
    /// Returns a list of the products in the cart.
    /// </summary>
    /// <returns></returns>
    IList<T> ListProducts();

    /// <summary>
    /// Remove all products from the cart;
    /// </summary>
    void ClearAllProducts();

    /// <summary>
    /// Add a promotion strategy to the cart.
    /// </summary>
    /// <param name="promotion"></param>
    void AddPromotion(IPromotion<T> promotion);
    /// <summary>
    /// Remove a promotion from the cart.
    /// </summary>
    /// <param name="promotion"></param>
    void RemovePromotion(string key);
    /// <summary>
    /// Remove all promotions from the cart.
    /// </summary>
    void ClearAllPromotions();

    /// <summary>
    /// List all of the promotions currently in the cart.
    /// </summary>
    /// <returns></returns>
    IList<IPromotion<T>> ListPromotions();

    /// <summary>
    /// Remove everything from the cart (promotions and all).
    /// </summary>
    void EmptyCart();
}

3 个答案:

答案 0 :(得分:1)

您可以使用Entity Framework的“Code First”功能。它允许您使用代码创建域类并将它们映射到db表。您可以在这些类中使用方法,其他属性等。

http://msdn.microsoft.com/en-us/data/gg685467.aspx

有一些限制,例如每个类必须具有默认构造函数,并且关联属性必须是虚拟的。但它们并没有那么成问题。

答案 1 :(得分:1)

一种方法是拥有两组类,其中一组代表您的POCO类,另一组代表实体框架类。您的POCO类将是Cart,Product等,并且将包含所有业务逻辑,并且当您想要编写产品时,例如,您可以手动将产品POCO类转换为Entity Framework产品类。 AutoMapper等框架。

作为一个想法,你可以有一个包含Entity Framework数据上下文的类,并将公开AddProduct等接受POCO类实例的方法。然后,此方法将其转换为Entity Framework Product实例并将其写入数据库。

此方法的缺点是您必须将POCO实例转换为实体框架实例,但它允许您与实体框架类分开使用POCO类。另外,您可以在不考虑数据库架构的情况下定义POCO。当您调用AddProduct并执行从POCO到Entity Framework的转换时,您可以在此时决定如何将POCO实例写入数据库。

编辑:另一种方法是使用@Dmitry S建议的Code-First,但Code-First推广使用Convention-over-Configuration方法,可以在创建POCO类时强制使用某些设计思路。

答案 2 :(得分:1)

你正确地想到了IProduct界面。

我会将可重复使用的购物车放在一个自己的程序集中 - 一个不知道持久性的程序(例如实体框架)。购物车组件将包含一个IProduct接口,您的应用程序的产品必须实现该接口。这样,购物车逻辑可以对使用它的应用程序(通过接口)设置要求。

如果您需要保留购物车,则必须将该持久性逻辑放在域层中。一种选择可能是将购物车用作代码优先实体,另一种选择是将数据映射到属于Db模型的实体类。