【问题标题】:Explicit construction of entity type '###' in query is not allowed.不允许在查询中显式构造实体类型“###”。
【发布时间】:2022-04-23 07:12:25
【问题描述】:

使用 Linq 命令和 Linq To SQL 数据上下文,我试图以这种方式从我的数据上下文中实例化一个名为“Produccion”的实体:

Demo.View.Data.PRODUCCION pocoProduccion = 
(
    from m in db.MEDICOXPROMOTORs
    join a in db.ATENCIONs on m.cmp equals a.cmp
    join e in db.EXAMENXATENCIONs on a.numeroatencion equals e.numeroatencion
    join c in db.CITAs on e.numerocita equals c.numerocita
    where e.codigo == codigoExamenxAtencion
    select new Demo.View.Data.PRODUCCION
    {
         cmp = a.cmp,
         bonificacion = comi,
         valorventa = precioEstudio,
         codigoestudio = lblCodigoEstudio.Content.ToString(),
         codigopaciente = Convert.ToInt32(lblCodigoPaciente.Content.ToString()),
         codigoproduccion = Convert.ToInt32(lblNroInforme.Content.ToString()),
         codigopromotor = m.codigopromotor,
         fecha = Convert.ToDateTime(DateTime.Today.ToShortDateString()),
         numeroinforme = Convert.ToInt32(lblNroInforme.Content.ToString()),
         revisado = false,
         codigozona = (c.codigozona.Value == null ? Convert.ToInt32(c.codigozona) : 0),
         codigoclinica = Convert.ToInt32(c.codigoclinica),
         codigoclase = e.codigoclase,
    }
).FirstOrDefault();

在执行上述代码时,我收到以下错误,包含堆栈跟踪:

System.NotSupportedException was caught
  Message="The explicit construction of the entity type 'Demo.View.Data.PRODUCCION' in a query is not allowed."
  Source="System.Data.Linq"
  StackTrace:
       en System.Data.Linq.SqlClient.QueryConverter.VisitMemberInit(MemberInitExpression init)
       en System.Data.Linq.SqlClient.QueryConverter.VisitInner(Expression node)
       en System.Data.Linq.SqlClient.QueryConverter.Visit(Expression node)
       en System.Data.Linq.SqlClient.QueryConverter.VisitSelect(Expression sequence, LambdaExpression selector)
       en System.Data.Linq.SqlClient.QueryConverter.VisitSequenceOperatorCall(MethodCallExpression mc)
       en System.Data.Linq.SqlClient.QueryConverter.VisitMethodCall(MethodCallExpression mc)
       en System.Data.Linq.SqlClient.QueryConverter.VisitInner(Expression node)
       en System.Data.Linq.SqlClient.QueryConverter.Visit(Expression node)
       en System.Data.Linq.SqlClient.QueryConverter.VisitFirst(Expression sequence, LambdaExpression lambda, Boolean isFirst)
       en System.Data.Linq.SqlClient.QueryConverter.VisitSequenceOperatorCall(MethodCallExpression mc)
       en System.Data.Linq.SqlClient.QueryConverter.VisitMethodCall(MethodCallExpression mc)
       en System.Data.Linq.SqlClient.QueryConverter.VisitInner(Expression node)
       en System.Data.Linq.SqlClient.QueryConverter.ConvertOuter(Expression node)
       en System.Data.Linq.SqlClient.SqlProvider.BuildQuery(Expression query, SqlNodeAnnotations annotations)
       en System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query)
       en System.Data.Linq.DataQuery`1.System.Linq.IQueryProvider.Execute[S](Expression expression)
       en System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source)
       en Demo.View.InformeMedico.realizarProduccionInforme(Int32 codigoExamenxAtencion, Double precioEstudio, Int32 comi) en D:\cs_InformeMedico\app\InformeMedico.xaml.cs:línea 602
       en Demo.View.InformeMedico.UpdateEstadoEstudio(Int32 codigo, Char state) en D:\cs_InformeMedico\app\InformeMedico.xaml.cs:línea 591
       en Demo.View.InformeMedico.btnGuardar_Click(Object sender, RoutedEventArgs e) en D:\cs_InformeMedico\app\InformeMedico.xaml.cs:línea 683
  InnerException: 

现在 LINQ2SQL 允许这样做吗?

【问题讨论】:

    标签: linq-to-sql


    【解决方案1】:

    实体可以在查询之外创建并使用 DataContext 插入到数据存储中。然后,您可以使用查询检索它们。但是,您不能创建实体作为查询的一部分。

    【讨论】:

    • 如何将返回查询中的选择值传递给实体,我的意思是不要使用成员,就像“varReturningQuery as ProductionEntity”一样?
    【解决方案2】:

    我发现这个限制非常烦人,并且违背了在查询中不使用 SELECT * 的普遍趋势。

    仍然有 c# 匿名类型的解决方法,通过将对象获取到匿名类型,然后将其复制到正确的类型。

    例如:

    var q = from emp in employees where emp.ID !=0
    select new {Name = emp.First + " " + emp.Last, EmployeeId = emp.ID }
    var r = q.ToList();
    List<User> users = new List<User>(r.Select(new User
       {
            Name = r.Name,
            EmployeeId = r.EmployeeId 
       }));
    

    如果我们处理单个值(如问题中描述的情况),则更容易,我们只需要直接复制值:

    var q = from emp in employees where emp.ID !=0 
    select new { Name = emp.First + " " + emp.Last, EmployeeId = emp.ID }
    var r = q.FirstOrDefault();
    User user = new User { Name = r.Name, EmployeeId = r.ID };
    

    如果属性名称与数据库列匹配,我们可以在查询中更简单地进行选择,方法是选择

    var q = from emp in employees where emp.ID !=0 
    select new { emp.First, emp.Last, emp.ID }
    

    可以继续编写一个 lambda 表达式,该表达式可以根据属性名称自动复制,而无需显式指定值。

    【讨论】:

    • 我同意这个限制很烦人。但是,在您的解决方案中调用 ToList 会将结果放入内存中,这对于大数据集来说可能是不可取的。
    【解决方案3】:

    这是另一种解决方法:

    1. 创建一个派生自 LINQ to SQL 类的类。我假设您要返回的 L2S 类是 Order:

      internal class OrderView : Order { }
      
    2. 现在这样写查询:

      var query = from o in db.Order
                  select new OrderView // instead of Order
                  {
                     OrderID = o.OrderID,
                     OrderDate = o.OrderDate,
                     // etc.
                  };
      
    3. 将结果重新转换为 Order,如下所示:

      return query.Cast<Order>().ToList(); // or .FirstOrDefault()
      
    4. (或者使用更合理的东西,比如 BLToolkit / LINQ to DB)

    注意:我还没有测试过跟踪是否有效;它可以检索数据,这正是我所需要的。

    【讨论】:

    • 太棒了!虽然我不需要回滚
    • 我同意这是一个很好的解决方案!如果有技术原因我不应该投影到实体类上,那很好,我不会,但是谁想重新定义一个具有完全相同形状的新(可能很长)类?没有人,就是那个人。该解决方案无需显式重新定义即可解决。干得好 pbz,搞定了。
    • 非常感谢这个回答 pbz!我不敢相信它的效果如何。我将在下面发布一个示例并感谢这个答案。
    【解决方案4】:

    我发现,如果您在尝试构造新对象之前对查询执行 .ToList() ,它会起作用

    【讨论】:

    • 但这会导致延迟执行。
    • 我找到的唯一解决方案是不推迟执行.......Select (p =&gt; new { anonymous columns }).ToList().Select(p =&gt; new TModel { Col1 = p.Col1, etc })
    【解决方案5】:

    我刚刚遇到了同样的问题。

    我找到了一个非常简单的解决方案。

    var a = att as Attachment;
    
    Func<Culture, AttachmentCulture> make = 
        c => new AttachmentCulture { Culture = c };
    
    var culs = from c in dc.Cultures
               let ac = c.AttachmentCultures.SingleOrDefault( 
                                               x => x.Attachment == a)
               select ac == null ? make(c) : ac;
    
    return culs;
    

    【讨论】:

    • select 最好写成 select ac ??制作(c);
    • 优秀的解决方案 - 谢谢!有什么想法为什么不这样做就不允许这样做?
    • @Whisk - 如果您仍然感兴趣,我发现 social.msdn.microsoft.com/forums/en-US/linqprojectgeneral/… - '...手动构造实体实例作为投影会污染缓存,并带有可能格式错误的对象...'
    【解决方案6】:

    我构造一个匿名类型,使用 IEnumerable(保留延迟执行),然后重新构造 datacontext 对象。 Employee 和 Manager 都是 datacontext 对象:

        var q = dc.Employees.Where(p => p.IsManager == 1)
                .Select(p => new { Id = p.Id, Name = p.Name })
                .AsEnumerable()    
                .Select(item => new Manager() { Id = item.Id, Name = item.Name });
    

    【讨论】:

    • AsEnumerable 不会导致急切加载吗?
    【解决方案7】:

    在“70-515 Web Applications Development with Microsoft .NET Framework 4 - Self-paced training kit”一书中,第 638 页有以下示例将结果输出到强类型对象:

        IEnumerable<User> users = from emp in employees where emp.ID !=0
        select new User
        {
        Name = emp.First + " " + emp.Last,
        EmployeeId = emp.ID
        }
    

    Mark Pecks 的建议似乎与这本书相矛盾——然而,对我来说,这个例子仍然显示上述错误,让我有些困惑。这与版本差异有关吗?欢迎提出任何建议。

    【讨论】:

    • 如果“用户”不是 DataContext 的一部分,则上述示例有效。
    【解决方案8】:

    我为该问题找到了另一种解决方法,它甚至可以让您将结果保留为 IQueryale,因此它实际上不会执行查询,直到您希望它被执行(就像使用 ToList() 方法一样)。

    所以 linq 不允许您创建实体作为查询的一部分?您可以将该任务转移到数据库本身并创建一个函数来获取您想要的数据。将函数导入数据上下文后,只需将结果类型设置为所需的类型即可。


    当我不得不编写一段代码来生成 IQueryable&lt;T&gt; 时,我发现了这一点,其中项目实际上并不存在于包含 T 的表中。

    【讨论】:

      【解决方案9】:

      pbz 通过创建一个继承自您可能正在使用的实体类的 View 类发布了一个解决方法。我正在使用具有 > 200 列的表的 dbml 模型。当我尝试返回整个表时,出现“缺少根元素”错误。我找不到任何想要处理我的特定问题的人,所以我正在考虑重写我的整个方法。在我的情况下,只需为实体类创建一个视图类即可。

      正如 pbz 建议的那样:创建一个继承自您的实体类的视图类。对我来说这是 tbCamp 所以:

          internal class tbCampView : tbCamp
          {
      
          }
      

      然后在查询中使用视图类:

      using (var dc = ConnectionClass.Connect(Dev))
              {
                  var camps = dc.tbCamps.Select(s => new tbCampView
                  {
                      active = s.active,
                      idCamp = s.idCamp,
                      campName = s.campName
                  });
      
                  
                  SmartTableViewer(camps, dg1);
              }
      
      private void SmartTableViewer<T>(IEnumerable<T> allRecords)
          {
              // Build sorted rows back into new table
              var table = new DataTable();
      
              // Create columns based on type
              if (allRecords is IEnumerable<tbCamp> tbCampRecords)
              {
                  // Get the columns you want
                  table.Columns.Add("idCamp");
                  table.Columns.Add("campName");
      
                  foreach (var record in tbCampRecords)
                  {
                      
                      // Make a new row
                      var r = table.NewRow();
      
                      // Add the contents to each column of the row
                      r["idCamp"] = record.idCamp;
                      r["campName"] = record.campName;
      
                      // Add the row to the table.
                      table.Rows.Add(r);
                  }
              }
              else
              {
                  MessageBox.Show("Unhandled type.  Add support for new data type in SmartTableViewer()");
                  return;
              }
      
              // Update table in grid
              dg1.DataSource = table.DefaultView;
          }
      

      当您尝试在查询中创建实体类对象时会发生以下情况。

      如果可以的话,我不想使用匿名类型,因为我希望类型是 tbCamp。由于 tbCampView 属于 tbCamp 类型,因此 is 运算符运行良好。请参阅 Brian Hasden 的回答 Passing a generic List<> in C#

      我很惊讶这甚至是一个问题,但是对于较大的表我遇到了这个错误,所以我想我会在这里展示它:

      尝试将此表读入内存时,出现以下错误。有 200。我不知道这是否是一个问题。

      如果我只想要几列,我需要创建一个自定义类并处理那些不是那么痛苦的事情。使用 pbz 提供的方法,我不必担心。

      这是整个项目,以防它对某人有所帮助。

      public partial class Form1 : Form
      {
          private const bool Dev = true;
      
          public Form1()
          {
              InitializeComponent();
          }
      
          private void btnGetAllCamps_Click(object sender, EventArgs e)
          {
              using (var dc = ConnectionClass.Connect(Dev))
              {
                  IQueryable<tbCampView> camps = dc.tbCamps.Select(s => new tbCampView
                  {
                      // Project columns as needed.
                      active = s.active,
                      idCamp = s.idCamp,
                      campName = s.campName
                  });
      
                  // pass in as a 
                  SmartTableViewer(camps);
              }
          }
      
          private void SmartTableViewer<T>(IEnumerable<T> allRecords)
          {
              // Build sorted rows back into new table
              var table = new DataTable();
      
              // Create columns based on type
              if (allRecords is IEnumerable<tbCamp> tbCampRecords)
              {
                  // Get the columns you want
                  table.Columns.Add("idCamp");
                  table.Columns.Add("campName");
      
                  foreach (var record in tbCampRecords)
                  {
                      //var newRecord = record;
                      // Make a new row
                      var r = table.NewRow();
      
                      // Add the contents to each column of the row
                      r["idCamp"] = record.idCamp;
                      r["campName"] = record.campName;
      
                      // Add the row to the table.
                      table.Rows.Add(r);
                  }
              }
              else
              {
                  MessageBox.Show("Unhandled type.  Add support for new data type in SmartTableViewer()");
                  return;
              }
      
              // Update table in grid
              dg1.DataSource = table.DefaultView;
          }
      
          internal class tbCampView : tbCamp
          {
      
          
          }
      

      }

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多