如何让EntityFramework检查2个参数?

时间:2014-06-30 15:19:01

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

我有3个相关对象(为简洁起见省略了非相关属性):

public class Product
{
    public int ID { get; set; }
    public virtual ProductPrice Price { get; set; }
}

public class ProductPrice
{
    public int     ID         { get; set; }
    public int     ProductID  { get; set; }
    public int     VerticalID { get; set; }
    public decimal Value      { get; set; }

    public virtual Product  Product  { get; set; }
    public virtual Vertical Vertical { get; set; }

    public override string ToString()
    {
        return Value.ToString("C");
    }
}

public class Vertical
{
    public int ID      { get; set; }
    public string Name { get; set; }
}

产品价格根据当前"垂直"而有所不同。当前的垂直可能(最终)存储在一个会话中,但暂时,我们假设这将是一个查询字符串参数。 (例如mydomain.com?VerticalID=2)。

我的问题

当用户访问mydomain.com/products?VerticalID=2mydomain.com/products/?VerticalID=2时,如何让实体框架根据ProductID 选择/分配正确的价格 - 使这成为可能?:

@Model.Price.ToString()

更新1(样本数据和数据库结构)

以下是我的虚拟内容表格:

产品

Products table

ProductPrices

ProductPrices table

垂直行业

Verticals table

关系解释

每个产品每个垂直应该有一个价格。查询看起来像:

-- Let's assume ProductID = 2 and VerticalID = 1 (e.g. mydomain.com/products/2?VerticalID=1)
SELECT * FROM ProductPrices WHERE ProductID = 2 AND VerticalID = 1

上面的查询将返回1行(它应该总是返回)


更新2(另一个例子)

为了便于说明,我将VerticalID属性添加到Product:

public class Product
{
    public int ID              { get; set; }
    public string Manufacturer { get; set; }
    public string Model        { get; set; }
    public string PartNumber   { get; set; }
    public int CategoryID      { get; set; }
    public string Description  { get; set; }

    [NotMapped]
    public int VerticalID = 1;

    public virtual ProductCategory Category { get; set; }
    public virtual ProductPrice Price { get; set; }
    public virtual ICollection<ProductImage> Images { get; set; }
    public virtual ICollection<ProductDocument> Documents { get; set; }
    public virtual ICollection<ProductDetail> Details { get; set; }
    public virtual ICollection<RelatedProduct> RelatedProducts { get; set; }
}

现在,当实际尝试执行此操作时,我收到以下错误:

Unable to determine the principal end of an association between the types 'Print_Solutions.Models.ProductPrice' and 'Print_Solutions.Models.Product'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.

如何在检索价格时告诉实体同时使用VerticalID和Product.ID?(使用我拥有的测试数据,如果这是产品1,则此产品应映射到ID 1产品价格表,成本100美元。

2 个答案:

答案 0 :(得分:2)

假设您的DbContext有一个名为ProductPrice ProductPrices的集合,使用LINQ,您只需进行此查询:

var price = ctx.ProductPrices.Where(pp =>
   pp.ProductId = productId && pp.VerticalId == verticalId).SingleOrDefault();

productIdverticalId是来自行动参数,会话或任何地方的可用参数。

使用单一或默认保证,即数据库中只有一个值,或者没有,并且在这种情况下,您会因查询而获得null。< / p>

至于您的更新,我发现您的问题也与模型中关系的定义有关。

有三种方法可以实现它:

  • 使用EF约定。要实现此目的,请更改您的entites的ID属性的名称:例如,使用ProductId而不是ID,并且约定将为您构建模型
  • 使用属性。在此特定情况下,请使用ForeignKeyAttribute适用的地方
  • using the fluent API

你有some more info on relationships here,只有一些简单的样本。

答案 1 :(得分:-1)

我无法弄清楚如何修复模型或使用流畅的API。我做了一些延迟加载。如果有人有更好的解决方案,请发布。

public class Product
{
    public int ID              { get; set; }
    public string Manufacturer { get; set; }
    public string Model        { get; set; }
    public string PartNumber   { get; set; }
    public int CategoryID      { get; set; }
    public string Description  { get; set; }

    public int VerticalID = 1;
    private ProductPrice _price;

    public virtual ProductCategory Category { get; set; }
    public virtual ICollection<ProductImage> Images { get; set; }
    public virtual ICollection<ProductDocument> Documents { get; set; }
    public virtual ICollection<ProductDetail> Details { get; set; }
    public virtual ICollection<RelatedProduct> RelatedProducts { get; set; }


    // Lazy Loading
    public ProductPrice Price
    {
        get
        {
            if (_price == null)
            {
                var db = new ApplicationContext();
                _price = db.Prices.FirstOrDefault(p => p.ProductID == ID && p.VerticalID == VerticalID);
            }

            return _price;
        }
    }
}