EntityFramework自定义sql查询虚拟属性

时间:2015-09-14 13:47:53

标签: c# sql-server entity-framework

我们使用6.1.2 EF,我们有从数据库生成的edmx。

我们有像POCO这样的课程:

public partial class Category
{
    public Category()
    {
        this.Products = new HashSet<Product>();
    }

    public long CategoryID { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Product> Products { get; set; }
}

我需要做的是插入具有自定义sql查询的新虚拟属性,如:

public virtual int ProductsCount { get; set; }

将返回select count(1) from dbo.Product where CatgoryID = *** 是否可以像这样定义虚拟财产?我在.edmx xml文件中找到了一些sql查询定义,所以我希望,也可以定义我的。我可以用什么来代替***?

毕竟,我的代码应该被称为简单:

context
    .Category
    .Include(x => x.ProductsCount)
    .ToList();

2 个答案:

答案 0 :(得分:1)

与生成的XML混淆在一般情况下不是一个好主意。任何重新生成都会覆盖您的代码。

IMO,您的财产应如下:

public int ProductCount { get { return Products.Count(); } }

您的请求应该是:

context.Category.Include(x => x.Products).ToList();

如果加载完整的产品列表可能会导致问题,我会使用DB View或带有计算列的Category表,然后更新我的EF映射以使这个新实体继承Category实体。

答案 1 :(得分:0)

如果Entity Framework具有公式属性,如NHibernate,这可能是一个可行的选择。但是,使用实体框架,您无法在不破坏持久性无知和生成n + 1个查询的情况下执行此操作。

  • 持久性无知:实体不应该对创建它们的数据层有任何引用。这是一个不应该被打破的重要命题。否则,您会创建一种难以跟踪(和预测)查询执行的时间和位置的情况。此外,它打破了单一责任原则。

  • n + 1反模式:除了具有公式属性的NHibernate之外,EF无法将嵌入式查询集成到它执行的查询中以从数据库中获取Category(1 )。每个类别随后将执行其自己的查询(n)。

执行此操作的最佳方法是将数据投影到视图模型(或DTO类,无论哪个名称最适合您):

context.Categories.Select(c => new CategoryModel
{
    Name = c.Name,
    OtherProperty = c.OtherProperty,
    ProductsCount = c.Products.Count()
}

在投影时,您应该始终关注 AutoMapper 可以为您做些什么。如果你有这个CategoryModel类,你可以定义一次映射(在应用程序启动时)......

Mapper.CreateMap<Catecory,CategoryModel>();

...并像这样使用它:

context.Categories.Project().To<CategoryModel>();

AutoMapper的优点在于它将ProductsCount之类的属性解析为源类Products中的属性,以及处理它的操作Count()。这一行代码与前面的代码片段完全相同。

附注:同样,AutoMapper解析嵌套属性。 CategoryName类中可能包含的属性ProductModel(如果产品类别为n-1)将解析为product.Category.Name