C# 我可以在使用Linq To实体时创建嵌套类吗?
我仍在学习实体框架和Linq To Entities,我想知道这样的陈述是否可行:C# 我可以在使用Linq To实体时创建嵌套类吗?,c#,entity-framework,linq-to-entities,C#,Entity Framework,Linq To Entities,我仍在学习实体框架和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 contex
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、字符串和Guid”)
这个背景
如果删除ModelB、ModelC和ModelD的映射,它将正确运行。我是否无法使用Linq to实体创建新的嵌套类?还是我写得不对?您所拥有的将与POCO(例如,视图模型)配合使用。你不能这样构造实体
另外,
join
将改为使用实体导航属性 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无法处理从查询中创建嵌套类的问题,我只需从查询中返回一个包含我想要的数据的匿名对象,然后将其映射到模型我已在控制台应用程序中使用EF 4.1创建了您的模型(我如何理解它):
如果要测试它,请添加对EntityFramework.dll
的引用,并将以下内容粘贴到Program.cs
(如果安装了SQL Server Express,EF 4.1会自动创建DB):
使用System.Linq;
使用System.Data.Entity;
命名空间EFNestedProjection
{
//实体
公共类模型A
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共模型B模型B{get;set;}
}
公共类模型B
{
公共int Id{get;set;}
公共字符串名称{get;set;}
}
公共类模型C
{
公共int Id{get;set;}
公共字符串名称{get;set;}
}
公共类模型
{
公共int Id{get;set;}
公共字符串名称{get;set;}
}
//上下文
公共类MyContext:DbContext
{
公共DbSet ModelSetA{get;set;}
公共DbSet modelseb{get;set;}
公共DbSet ModelSetC{get;set;}
公共DbSet ModelSetD{get;set;}
}
//投影的视图模型,而不是实体
公共类MyModelA
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共mymodelbmodelb{get;set;}
公共MyModelC ModelC{get;set;}
公共MyModelD ModelD{get;set;}
}
公共类MyModelB
{
公共int Id{get;set;}
公共字符串名称{get;set;}
}
公共类MyModelC
{
公共int Id{get;set;}
公共字符串名称{get;set;}
}
公共类MyModelD
{
公共int Id{get;set;}
公共字符串名称{get;set;}
}
班级计划
{
静态void Main(字符串[]参数)
{
//在数据库中创建一些实体
使用(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();
}
//运行查询
使用(var ctx=new MyContext())
{
var结果=(
从ctx.ModelSetA.Include中的a开始(“ModelB”)
在ctx.ModelSetC中加入c,a.Id等于c.Id
在ctx.ModelSetD中加入d,a.Id等于d.Id
选择newmymodela()
{
Id=a.Id,
Name=a.Name,
ModelB=新的MyModelB(){
Id=a.ModelB.Id,Name=a.ModelB.Name},
ModelC=新的MyModelC(){
Id=c.Id,Name=c.Name},
ModelD=新的MyModelD(){
Id=d.Id,Name=d.Name}
}).FirstOrDefault();
//这里也不例外
}
}
}
}
这是没有问题的。(我还从EF 4.0中的数据库(EF 4.1创建的)重新创建了模型:它也可以工作。这并不奇怪,因为EF 4.1没有将LINQ中的任何内容更改为实体。)
现在的问题是,为什么会出现异常?我的猜测是,与上面的简单模型相比,您的模型或ViewModels或查询有一些重要的区别,这在问题中的代码示例中是不可见的
但总的结果是:向嵌套(非实体)类的投影起作用。(我在很多情况下使用它,即使是嵌套的集合。)您的问题标题的答案是:是。但是我发布的代码不起作用-它给出了我上面发布的错误。如果我删除嵌套类并仅返回
ModelA
,但如果我将它们保留在中,则它不起作用。此外,我很想使用Nav属性来实现这一点,但我不允许接触数据库结构,而且数据库设计糟糕,因此EF在尝试将我的自定义表与预先存在的表连接时给了我各种各样的麻烦。此外,还有类(MyModelA
,MyModelB
,等等)我现在使用的基本上是带有PropertyChange
通知的POCO,而不是Entit
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
}
}
}
}