有效操作时出现NullReferenceException异常

9

我需要从一个查询中获取我的ID(类型为Guid):

var firstQuery = 
    from rooms in myEntityContext.Room.Where(t => t.fldClosed == 0)
    join conts in myEntityContext.Cont on rooms.ID equals conts.ItemID
    select new
    {
        ContPrice = conts.Price,
        RoomPrice = rooms.Price
        IDs = rooms.ID
    };

foreach (var t in firstQuery)
{
    t.RoomPrice  = t.ContPrice;
}

然后我对它执行一些操作(更新价格),最后我使用这些ID进行第二次查询。那第二次查询不包含这些ID。我是这样解决这个问题的:

var myIDs = firstQuery.Select(cr => cr.IDs).ToList();

我的第二个问题是:
var secondQuery = 
    from rooms in myEntityContext.Room.Where(t => t.fldClosed == 0) 
    where !myIDs.Contains(rooms.fldID)                                   
    join conts in myEntityContext.Cont on rooms.ID equals conts.ItemID
    select new
    {
       RoomPrice = conts.fldPrice,
       IDs = rooms.ID
    };

当我以调试模式运行这段代码并到达这一行时:
var myIDs = firstQuery.Select(cr => cr.IDs).ToList();

当抛出异常时:

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

似乎与第二个查询有关,因为当我将第二个查询转移到单独的方法中并传递ID时,一切都运行完美,但我无法理解为什么它应该考虑在变量初始化之后编写的某些查询。

整个代码如下:

var calcDate = DateTime.Now.AddDays(-1);

var firstQuery = 
    from rooms in myEntityContext.Room.Where(t => t.fldClosed == 0)
    join conts in myEntityContext.Cont on rooms.ID equals conts.ItemID
    where conts.date == calcDate
    select new
    {
        ContPrice = conts.Price,
        RoomPrice = rooms.Price
        IDs = rooms.ID
    };

foreach (var t in firstQuery)
{
    t.RoomPrice = t.ContPrice;
}

var myIDs = firstQuery.Select(cr => cr.IDs).ToList();


var secondQuery = 
    from rooms in myEntityContext.Room.Where(t => t.fldClosed == 0) 
    where !myIDs.Contains(rooms.fldID)                                   
    join conts in myEntityContext.Cont on rooms.ID equals conts.ItemID
    where conts.date == calcDate && conts.Code = "01"
    select new
    {
       RoomPrice = conts.fldPrice,
       IDs = rooms.ID
    };

foreach (var t in secondQuery)
{
    ContPrice = Conts.Price,
    RoomPrice = Rooms.Price
}

myEntityContext.SaveChanges();

下面是我的堆栈跟踪,如果有用:

Financial.UI.dll!Financial.UI.Services.Hotels.HotelServiceProxy.CalcProxy.DoCalc(System.DateTime calcDate) Line 5055    C#
Financial.UI.dll!Financial.UI.Pages.Hotel.NightsCalculationPage.CallbackMethod_DoCalc() Line 65 + 0x37 bytes    C#
[Native to Managed Transition]  
Web.UI.dll!Web.UI.SystemCallback.ProcessCallback() Line 228 + 0x3b bytes    C#
Web.UI.dll!Web.UI.SystemCallbackHandler.ProcessRequest(System.Web.HttpContext context) Line 68 + 0x12 bytes C#
System.Web.dll!System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() + 0x156 bytes    
System.Web.dll!System.Web.HttpApplication.ExecuteStep(System.Web.HttpApplication.IExecutionStep step, ref bool completedSynchronously) + 0x46 bytes 
System.Web.dll!System.Web.HttpApplication.PipelineStepManager.ResumeSteps(System.Exception error) + 0x342 bytes 
System.Web.dll!System.Web.HttpApplication.BeginProcessRequestNotification(System.Web.HttpContext context, System.AsyncCallback cb) + 0x60 bytes 
System.Web.dll!System.Web.HttpRuntime.ProcessRequestNotificationPrivate(System.Web.Hosting.IIS7WorkerRequest wr, System.Web.HttpContext context) + 0xbb bytes   
System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) + 0x1f3 bytes   
System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) + 0x1f bytes  
[Native to Managed Transition]  
[Managed to Native Transition]  
System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) + 0x350 bytes   
System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) + 0x1f bytes  
[Appdomain Transition]  
该文本是一个堆栈跟踪,它显示了在运行代码时发生错误的位置。具体来说,它显示了在哪个方法中发生错误,以及在调用该方法的时候有哪些上下文和参数。

3
也许一个完整的堆栈帧会有所帮助。 - Simon Mourier
我认为foreach循环可能会引起问题。你为什么不在select new中将Counts.Price分配给CountPriceRoomPrice呢? - Dzienny
1
@MaryamArshi,你真的需要在异常发生时提供堆栈跟踪。否则我们无法帮助你。我怀疑异常发生在你指定的那一行。在Visual Studio中,你还可以从抛出的“Exception”中获取堆栈跟踪字符串。只需复制它并添加到你的帖子中即可。 - Daniel A.A. Pelsmaeker
1
@MaryamArshi 你应该在这里发布堆栈跟踪。对于解决此类异常,它是最重要的信息。由于您无法找出为什么会出现此异常,请让其他人来查看。 - Daniel A.A. Pelsmaeker
1
@Maryam 以“发布”版本运行代码,你可能不会遇到任何错误。 - Dzienny
显示剩余13条评论
5个回答

5

嗯,堆栈跟踪是有用的:我假设您发布的代码在DoCalc()方法中。然而,您发布的那一行不可能是您代码中的第5055行:

var myIDs = firstQuery.Select(cr => cr.IDs).ToList();

要在此行发生NullReferenceException,则firstQuery必须为null或firstQuery.Select(cr => cr.IDs)必须返回null...但是,如果是这种情况,你将在两种情况下都收到ArgumentNullException,而不是NullReferenceException。所以错误不在这一行。
另外,你的代码甚至不应该运行!例如,在以下代码片段中,你应该会得到一个编译时错误:
foreach (var t in firstQuery)
{
    t.RoomPrice = t.ContPrice;
}

无法分配属性或索引器“AnonymousType#1.RoomPrice”-- 它是只读的

而你在这里尝试做什么……我不知道:

foreach (var t in secondQuery)
{
    ContPrice = Conts.Price,
    RoomPrice = Rooms.Price
}

最可能发生的情况

你在 myEntityContext.Room 或者 myEntityContext.Cont 中有一个 null。看一下它们的内容并进行验证。如果你还不确定,在Visual Studio中获取异常时,在异常窗口上单击 "将异常详细信息复制到剪贴板" 并将其粘贴到你的问题中。


这只是一个简单的查询来更新价格,我没有在主查询中执行此操作,因为以后我想要添加一些更多的计算。但是我之前的代码行没有任何编译错误,不过我会再次检查它们。谢谢。 - Maryam Arshi

3

这段代码无法编译。假设它曾经编译过,并且您的所有房间和Cont都是实际存在的实例,其中没有空对象,则可能是使用了匿名的return;语句。

请尝试以下方法:

public class QueryResult
{
    public decimal ContPrice; //whatever your types are

    public decimal RoomPrice;

    public int IDs;
}

然后像这样使用它:
var firstQuery =
    from rooms in myEntityContext.Room.Where(t => t.fldClosed == 0)
    join conts in myEntityContext.Cont on rooms.ID equals conts.ItemID
    where conts.date == calcDate
    select new QueryResult
                {
                    ContPrice = conts.Price,
                    RoomPrice = rooms.Price,
                    IDs = rooms.ID
                };

var firstQueryResult = firstQuery.ToList();

foreach (var t in firstQueryResult)
{
    t.RoomPrice = t.ContPrice;
}

正如其他人所言,避免多次枚举。

同时删除第二个查询并最初获取第一个工作...你在第二个查询中有一些问题。首先,你再次使用匿名类型作为结果。这是一种滥用,因为它们应该在linq之间使用;你应该转换为强类型。其次,

... && conts.Code = "01"

不能编译,应该改为:

conts.Code.Equals("01")

我建议将您的查询分成较小的部分;可能是这样的:
var roomsOpenQuery = myEntityContext.Room.Where(t => t.fldClosed == 0);
var roomsOpenQueryResolved = roomsOpenQuery.ToList();
var contQuery = myEntityContext.Cont
    .Where(t => roomsOpenQueryResolved.Any(r => r.ID == t.ItemID))
    .Where(x => x.date == calcDate);


var availableRooms =
    contQuery
        .Join(roomsOpenQueryResolved,
                c => c.ItemID,
                r => r.ID,
                (c, r) => new AvailableRoom()
                            {
                                ContPrice = c.Price,
                                RoomPrice = r.Price,
                                IDs = c.ItemID
                            })
        .ToList();


//Price Adjustment etc...

2

我假设var FirstQuery解析为IEnumerable< out T >。

您不能多次访问Enumerable的内容。

尝试在第一个查询中创建List:

var FirstQuery = (from rooms in myEntityContext.Room.Where(t => t.fldClosed == 0)                                    
    join Conts in myEntityContextt.Cont on rooms.ID equals Conts.ItemID
    select new
    {
        RoomPrice = Conts.fldPrice,
        IDs = rooms.ID
    }).ToList();

如果这行代码失败了,那么myEntityContext.Mark或myEntityContext.Cont很可能是空对象。

我也尝试了这个解决方案,但它也没有起作用。我的查询中没有空值,它返回大约826行数据,我已经检查过它们不是空的。无论如何还是谢谢。 - Maryam Arshi
1
@qujck 一般情况下,您可以多次访问可枚举内容。只有一些非常特定的可枚举可能在重新枚举时不产生相同的结果。 - Daniel A.A. Pelsmaeker

1

IDs表示房间的ID,可能为空。请尝试添加以下代码:

var myIDs = FirstQuery.ToList().Select(Cr => Cr.IDs).ToList();


1
var myIDs = new List<int>();
if( firstQuery.Count() > 0)
myIds =  firstQuery.Select(cr => cr.IDs).ToList();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接