使用Linq-To-Entities时可以创建嵌套类吗?

时间:2011-09-30 19:37:08

标签: c# entity-framework linq-to-entities

我还在学习Entity Framework和Linq-To-Entities,我想知道这种声明是否可行:

using (var context = new MyEntities())
{
    return (                    
        from a in context.ModelSetA.Include("ModelB")
        join c in context.ModelSetC on a.Id equals c.Id
        join d in context.ModelSetD on a.Id equals d.Id
        select new MyModelA()
        {
            Id = a.Id,
            Name = a.Name,
            ModelB = new MyModelB() { Id = a.ModelB.Id, Name = a.ModelB..Name },
            ModelC = new MyModelC() { Id = c.Id, Name = c.Name },
            ModelD = new MyModelD() { Id = d.Id, Name = d.Name }
        }).FirstOrDefault();
}

我必须使用预先存在的数据库结构,这种结构不是很优化,因此我无法在没有大量额外工作的情况下生成EF模型。我认为简单地创建我自己的模型并将数据映射到它们会很容易,但我不断收到以下错误:

  

无法创建“MyNamespace.MyModelB”类型的常量值。只要   支持原始类型(例如Int32,String和Guid')   这个背景。

如果删除ModelB,ModelC和ModelD的映射,它将正确运行。我无法使用Linq-To-Entities创建新的嵌套类?或者我只是以错误的方式写这个?

3 个答案:

答案 0 :(得分:4)

您拥有的内容可以与POCO(例如,视图模型)一起使用。 Here's an example.你无法以这种方式构建实体。

此外,joingenerally inappropriate for a L2E query.请改用实体导航属性。

答案 1 :(得分:2)

我在控制台应用程序中使用EF 4.1创建了您的模型(我如何理解它):

如果要对其进行测试,请添加对EntityFramework.dll的引用,并将以下内容粘贴到Program.cs中(如果安装了SQL Server Express,则自动创建数据库):

using System.Linq;
using System.Data.Entity;

namespace EFNestedProjection
{
    // Entities
    public class ModelA
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public ModelB ModelB { get; set; }
    }

    public class ModelB
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class ModelC
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class ModelD
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    // Context
    public class MyContext : DbContext
    {
        public DbSet<ModelA> ModelSetA { get; set; }
        public DbSet<ModelB> ModelSetB { get; set; }
        public DbSet<ModelC> ModelSetC { get; set; }
        public DbSet<ModelD> ModelSetD { get; set; }
    }

    // ViewModels for projections, not entities
    public class MyModelA
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public MyModelB ModelB { get; set; }
        public MyModelC ModelC { get; set; }
        public MyModelD ModelD { get; set; }
    }

    public class MyModelB
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class MyModelC
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class MyModelD
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // Create some entities in DB
            using (var ctx = new MyContext())
            {
                var modelA = new ModelA { Name = "ModelA" };
                var modelB = new ModelB { Name = "ModelB" };
                var modelC = new ModelC { Name = "ModelC" };
                var modelD = new ModelD { Name = "ModelD" };

                modelA.ModelB = modelB;

                ctx.ModelSetA.Add(modelA);
                ctx.ModelSetB.Add(modelB);
                ctx.ModelSetC.Add(modelC);
                ctx.ModelSetD.Add(modelD);

                ctx.SaveChanges();
            }

            // Run query
            using (var ctx = new MyContext())
            {
                var result = (
                    from a in ctx.ModelSetA.Include("ModelB")
                    join c in ctx.ModelSetC on a.Id equals c.Id
                    join d in ctx.ModelSetD on a.Id equals d.Id
                    select new MyModelA()
                    {
                        Id = a.Id,
                        Name = a.Name,
                        ModelB = new MyModelB() {
                            Id = a.ModelB.Id, Name = a.ModelB.Name },
                        ModelC = new MyModelC() {
                            Id = c.Id, Name = c.Name },
                        ModelD = new MyModelD() {
                            Id = d.Id, Name = d.Name }
                    }).FirstOrDefault();
                // No exception here
            }
        }
    }
}

这没有问题。 (我还在EF 4.0中重新创建了数据库中的模型(EF 4.1创建了这个模型):它也很有用。因为EF 4.1不会改变LINQ to Entities中的任何内容,所以不足为奇。)

现在问题是为什么你得到一个例外?我的猜测是,与上面的简单模型相比,您的模型或ViewModel或查询存在一些重要差异,这些模型在问题的代码示例中不可见。

但一般结果是:对嵌套(非实体)类的预测有效。 (我在许多情况下都使用它,即使是嵌套的集合。)回答你的问题标题是:是的。

答案 2 :(得分:0)

Craig发布的内容似乎不适用于嵌套实体。克雷格,如果我误解了你发布的内容,请纠正我。

以下是我提出的可行的解决方法:

using (var context = new MyEntities())
{
    var x = (                    
        from a in context.ModelSetA.Include("ModelB")
        join c in context.ModelSetC on a.Id equals c.Id
        join d in context.ModelSetD on a.Id equals d.Id
        select new { a, b, c }).FirstOrDefault();

    if (x == null)
        return null;

    return new MyModelA()
        {
            Id = x.a.Id,
            Name = x.a.Name,
            ModelB = new MyModelB() { Id = x.a.ModelB.Id, Name = x.a.ModelB..Name },
            ModelC = new MyModelC() { Id = x.c.Id, Name = x.c.Name },
            ModelD = new MyModelD() { Id = x.d.Id, Name = x.d.Name }
        };
}

由于Entity Framework无法处理从查询中创建嵌套类的问题,我只是从查询中返回一个包含我想要的数据的匿名对象,然后将其映射到模型