【问题标题】:LINQ's .Union() with unknown data typesLINQ 的 .Union() 具有未知数据类型
【发布时间】:2016-06-02 12:37:23
【问题描述】:

我需要从不同的数据库中获取数据,然后将这两个数据集组合成一个 IQueryable 集合。

数据库#1 数据示例:

-- SOLUTION #1
[ID] [int],
[Name] [nvachar](50),
[ExpirationDate] [datetime],
[Users] [int]

Databse #2 数据示例:

-- SOLUTOIN #1
[ID] [int],
[Name] [nvarchar](50),
[Users] [int]

如您所见,数据库#2 中的解决方案没有ExpirationDate 属性,这给我在执行Union() 时带来了一些问题。


我尝试了以下方法:

public static IQueryable GetAll()
{
    var list = (from solution1 in db1.Solutions
            select new
            {
                Id = solution1.ID,
                Name = solution1.Name,
                ExpirationDate = solution1.ExpirationDate,
                Users = solution1.Users
            })
        .Union(from solution2 in db2.Solutions
            select new{
                Id = solution2.ID,
                Name = solution2.Name,
                ExpirationDate = (DateTime?) null,
                Users = solution2.Users        
            });
}

但不幸的是,这不起作用。调用它时,我得到以下异常:

对象引用未设置为对象的实例。

我想这是因为我设置了ExpirationDate = (DateTime?) null


我也尝试过从 SQL 视图中获取数据,就像这样(这是db2 的示例,因为db1 有点不言自明

CREATE VIEW [dbo].[v_Solutions]
    AS SELECT s.ID,
        s.Name,
        null AS [ExpirationDate],
        s.Users
    FROM Solution

然后将 LINQ select new 语句更改为以下内容:

.Union(from solution2 in db2.Solutions
            select new{
                Id = solution2.ID,
                Name = solution2.Name,
                ExpirationDate = (DateTime?) solution2.ExpirationDate,
                Users = solution2.Users        
            });

但是这样做会给我一个编译错误:

无法转换类型“int?”到“System.DateTime?”

虽然solution2.ExpirationDate 中的数据应该只是null

我不太确定如何完成此声明。有什么想法吗?

【问题讨论】:

  • 如果您使用 EF 对两个数据库进行查询,我会假设您需要在内存中进行联合。所以在Union 之前打一个AsEnumerable 并在Union 内的查询末尾打另一个。
  • 确保solution1solution2 本身不为空......例如以这种方式跳过它们(from solution1 in db1.Solutions where (solution1 != null) select new .....
  • 只是做null AS [ExpirationDate] 可能无法推断出正确的类型,因此 CAST 或 CONVERT null as datetime 可能会起作用(在视图内)?
  • @M.kazemAkhgary 我的solution1 实际上是null。我想知道为什么,但至少我发现了这个问题。
  • 如果你的集合中有 null 是预期的,那么不用担心你可以用 where 省略它们。但是,如果您的集合中预计不会有空项目,请不要用where 省略它们。尝试找出导致空元素的主要问题...

标签: c# sql-server linq


【解决方案1】:

LINQ 2 SQL 和 EF 不支持从多个数据库上下文中提取的查询。显然,您甚至触发了导致NullReferenceException 的错误。

你可以在内存中执行联合:

db1.SomeTable.AsEnumerable().Union(db2.SomeTable.AsEnumerable())

如果你想在数据库中执行联合,你需要使用原始 SQL,或者将一些表映射到 DBML 中的另一个数据库,或者使用表值函数或视图。

【讨论】:

  • 但我不能使用 AsEnumerable() 。检查我的函数返回类型
  • @Detilium 您必须将返回类型更改为IEnumerable,实际上您应该使用自定义类将您的值投影到其中,这样您就可以使用IEnumerable<MySolutionClass> 之类的东西进行强类型化。
  • 我向您展示的代码只是一个简单的操作示例,与我的实际代码相比,这算不了什么。我需要它是 IQueryable,并且我不会更改返回类型。
  • 您不能跨上下文查询,期间。也许你只需要一个假的可查询?在最终结果上致电AsQueryable()。如果不知道您想要实现什么以及为什么会有这些限制,就很难推荐一个具体的解决方案。
【解决方案2】:

在第二种情况下尝试:

CREATE VIEW [dbo].[v_Solutions]
    AS SELECT s.ID,
        s.Name,
        CAST(NULL as DateTime)  AS [ExpirationDate],
        s.Users
    FROM Solution

【讨论】:

  • 您不应将 ADO.Net 的 DBNull 与 Linq SQL 提供程序混合使用。它应该为您在DBNullnull 之间进行翻译。
  • @juharr 无论如何都不起作用,因为System.DBNull.Value 不对应于第一个 select 语句
  • 这个答案很可能有效,因为该类型现在被识别为Datetime?。我的问题是我的条目是null,抛出NullReferenceException。我的问题与这个问题的主题不同。
【解决方案3】:

尝试以这种方式修改第一个查询:

// ...
ExpirationDate = (DateTime?)solution1.ExpirationDate,

更新:

我尝试重新创建您的案例,这似乎有效:

using System.Collections.Generic;
using System.Threading.Tasks;
using System.Data.Entity;
using System.Linq;  
using System;

public class Program
{
    public static void Main()
    {
        var itemsA = new[]{new ItemA {Name = "a", Date = DateTime.Now}};
        var itemsB = new[]{new ItemB {Name = "b" }};


        var list = (from solution1 in itemsA
            select new
            {
                Name = solution1.Name,
                Date = (DateTime?)solution1.Date
            })
        .Union(from solution2 in itemsB
            select new{
                Name = solution2.Name,
                Date = (DateTime?)null                
            });

        Console.WriteLine(list.Count());

    }
    public class ItemA
    {
        public string Name {get;set;}
        public DateTime Date {get;set;}
    }
    public class ItemB
    {
        public string Name {get;set;}

    }

}

【讨论】:

  • 我试图重新创建您的案例(请参阅更新的答案)。想知道自己缺少什么。
【解决方案4】:

我完全搞砸了。我的db1db2 实例一直为空。我的代码中的某些内容无法正常工作。我现在有另一个问题,但是NullReferenceException 不见了。

【讨论】:

  • 您应该将此信息添加到问题中。但这无关紧要,因为这种方法无法满足您的要求。正如你所说,你只会得到另一个不同的错误。
猜你喜欢
  • 1970-01-01
  • 2020-03-29
  • 2022-01-04
  • 1970-01-01
  • 1970-01-01
  • 2019-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多