【问题标题】:Entity Framework - Conditionally include related entities实体框架 - 有条件地包括相关实体
【发布时间】:2013-12-11 05:52:55
【问题描述】:

我维护了一个 API,它根据对人员列表的请求,根据请求返回不同的结果集。例如,一些 API 客户端想要获取人员列表和他们的交互列表,其他 API 客户端想要人员和他们的元数据列表。所有这些都可以在他对返回人员的 API 方法的请求中指定。

这似乎不起作用:

using (var dbcontext = new ExampleEntities())
{
    var query = dbcontext.People.AsQueryable();
    //determined in earlier application logic based on request
    if(includeMetadata)
    {
        query = query.Include("metadata");
    }
    //determined in earlier application logic based on request
    if(includeInteractions) 
    {
        query = query.Include("interactions");
    }
    /* ...SNIP... */
}

我不想做的是:

var query = dbcontext.People.Include("Metadata").Include("interactions");

这意味着每个获取人员的请求都将包括其所有相关实体,即使请求的 API 客户端不需要它们。

我也不想编写所有可能的逻辑组合:

if(includeMetadata && includeInteractions)
{
    var query = dbcontext.People.Include("Metadata").Include("interactions");

}
else if(includeMetadata)
{
    var query = dbcontext.People.Include("Metadata");
}
else if(includeInteractions)
{
    var query = dbcontext.People.Include("Interactions");
}
else
{
    var query = dbcontext.People;
}

这将导致难以维护的代码,但是,我意识到如果需要我可以通过代码生成它。

【问题讨论】:

    标签: c# entity-framework


    【解决方案1】:

    你可以链接 IQueryable 的

    using (var dbcontext = new ExampleEntities())
    {
        var query = dbcontext.People.AsQueryable();
        if(includeMetadata)
        {
            query = query.Include("metadata");
        }
        if(includeInteractions) 
        {
            query = query.Include("interactions");
        }    
    }
    

    【讨论】:

    • 这是否仅在不同版本的实体框架中可用?我收到以下错误:错误 37“System.Linq.IQueryable”不包含“Include”的定义,并且没有扩展方法“Include”接受“System.Linq.IQueryable”类型的第一个参数可以找到(您是否缺少 using 指令或程序集引用?)也许还缺少扩展程序集?
    • 链接是 LINQ 的标准功能。但是Include 是一种 EF 扩展方法 (msdn.microsoft.com/en-us/library/gg696450%28v=vs.103%29.aspx),需要引用 EntityFramework.dll 程序集并添加 using System.Data.Entity; 也会删除 AsQueryable()
    • 好的。我很困惑,因为我可以在 dbcontext.SomeTable 上调用 .Include 但不能在 someQuery 上调用。添加所需的导入后,它工作正常。我已经在引用 EntityFramework.dll
    【解决方案2】:

    如果您将u 替换为query,您的第一个示例应该可以工作

     u = u.Include("metadata");
    

     query = query.Include("metadata");
    

    【讨论】:

    • 错字-对不起!错字只存在于问题中
    【解决方案3】:

    在这里工作正常...使用 EF 6 日志处理程序检查 sql 语句

    [TestClass]
    public void SomeTestClass
    {
        [TestMethod]
        public void ShouldLoadOnlyRequiredCollections()
        {
            Database.SetInitializer(new DropCreateDatabaseAlways<HomesContext>());
    
            var db = new HomesContext();
    
            Assert.IsFalse(db.Homes.Any());
    
            var home = db.Homes.Create();
    
            db.Homes.Add(home);
    
            home.Staff.Add(new Staff { Name = "wilma" });
            home.Staff.Add(new Staff { Name = "betty" });
    
            home.Residents.Add(new Resident { Name = "fred" });
            home.Residents.Add(new Resident { Name = "barney" });
    
            db.SaveChanges();
    
            db = null;
    
            Database.SetInitializer(new DropCreateDatabaseIfModelChanges<HomesContext>());
    
            var sb = new StringBuilder();
            db = new HomesContext();
    
            db.Database.Log = ((s) => { sb.Append(s + "\r"); });
    
            Assert.IsTrue(db.Homes.Any());
    
            string log;
    
            log = sb.ToString();
    
            Assert.IsTrue(sb.ToString().Contains("FROM [dbo].[Homes]"));
    
            sb = new StringBuilder(); //ok get residents
    
            var q = db.Homes.Include("Residents");
    
            Assert.IsTrue(string.IsNullOrEmpty(sb.ToString()));
    
            var lst = q.ToList();
    
            log = sb.ToString();
    
            Assert.IsTrue(sb.ToString().Contains("[dbo].[Homes]"));
            Assert.IsTrue(sb.ToString().Contains("[dbo].[Residents]"));
            Assert.IsTrue(!sb.ToString().Contains("[dbo].[Staff]"));
    
            sb = new StringBuilder(); //get staff
    
            q = db.Homes.Include("Staff");
    
            Assert.IsTrue(string.IsNullOrEmpty(sb.ToString()));
    
            lst = q.ToList();
    
            log = sb.ToString();
    
            Assert.IsTrue(log.Contains("[dbo].[Homes]"));
            Assert.IsTrue(!log.Contains("[dbo].[Residents]"));
            Assert.IsTrue(log.Contains("[dbo].[Staffs"));
    
    
    
            sb = new StringBuilder(); //get residents and staff
    
            q = db.Homes.Include("Staff");
    
            q = q.Include("Residents");
    
            lst = q.ToList();
    
            log = sb.ToString();
    
            Assert.IsTrue(log.Contains("[dbo].[Homes]"));
            Assert.IsTrue(log.Contains("[dbo].[Residents]"));
            Assert.IsTrue(log.Contains("[dbo].[Staffs]"));
    
    
    
    
        }
    }
    
    public class HomesContext:DbContext
    {
        public DbSet<Home> Homes { get; set; }
    }
    
    public class Home
    {
        public Home()
        {
            Staff = new List<Staff>();
            Residents = new List<Resident>();
        }
        public int HomeId { get; set; }
        public string HomeName { get; set; }
    
        public int MaxResidents { get; set; }
        public int MaxStaff { get; set; }
    
        public int CurrentResidents { get; set; }
    
        [NotMapped]
        public int CurrentStaff { get; set; }
    
        public IList<Staff> Staff { get; set; }
        public IList<Resident> Residents { get; set; }
    }
    
    public class Staff
    {
        public int StaffId { get; set; }
        public string Name { get; set; }
        public int HomeId { get; set; }
        public Home Home { get; set; }
    }
    
    public class Resident
    {
        public int ResidentId { get; set; }
        public string Name { get; set; }
    
        public int HomeId { get; set; }
        public Home Home { get; set; }
    }
    

    【讨论】:

    • 不确定你的意思。我怎么查。它正在关闭一个视图。
    • 我会检查 EntityFramework 的版本,如果有必要尝试升级它
    • 您可以执行msg = q.ToString(),这将为您提供查询将尝试触发的 SQL,或者您可以运行 Sql Profiler。但是 EF 6 很好..
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-21
    • 1970-01-01
    • 1970-01-01
    • 2014-10-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多