Tôi có ba lớp thực thể liên quan sau đây:Strange null trong LINQ truy vấn với EF
public class ContextInstance
{
public Int64 Id { get; set; }
public virtual List<ContextParamValue> ContextParamValues { get; set; }
}
public class ContextParamValue
{
public Int64 Id { get; set; }
public virtual Int64 ContextParamId { get; set; }
public virtual ContextParam ContextParam { get; set; }
public virtual ContextInstance ContextInstance { get; set; }
public virtual Int64 ContextInstanceId { get; set; }
public string Value { get; set; }
}
public class ContextParam
{
public Int64 Id { get; set; }
[Required]
public string Name { get; set; }
[DefaultValue("")]
public string Description { get; set; }
}
Tôi đã thiết lập mối quan hệ thông thạo như sau:
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
modelBuilder.Entity<ContextInstance>()
.HasMany(ci => ci.ContextParamValues)
.WithRequired(cpv => cpv.ContextInstance)
.HasForeignKey(cpv => cpv.ContextInstanceId)
.WillCascadeOnDelete(true);
tôi có lớp "Trình trợ giúp" sau, phương thức ParamValueToList trong đó liên tục ném một ngoại lệ không tham chiếu null :
public class RuntimeHelper : IDisposable
{
DocumentDbContext db;
ConfigurationHelper ch;
private RuntimeHelper()
{
}
public RuntimeHelper(DocumentDbContext context)
{
db = context;
ch = new ConfigurationHelper(context);
}
public List<ContextParamValue> ParamValuesToList(string[] ParamNames, string[] ParamValues)
{
Trace.TraceInformation("-- ParamValuesToList invoked --");
if (ParamNames != null && ParamNames.Length != ParamValues.Length)
throw new System.ArgumentException("ParamNames and ParamValues may not differ in length.");
Dictionary<string, string> d = new Dictionary<string, string>();
for (int i = 0; i < ParamNames.Length; i++)
{
string pName = ParamNames[i];
string pValue = ParamValues[i];
d.Add(pName, pValue);
Trace.TraceInformation("ParamValuesToList Key: " + pName + "; Value: " + pValue + ";");
}
Trace.TraceInformation("Value of db:" + db.ContextParamValues.ToString());
var cpvList = db.ContextParamValues
.Include(x => x.ContextParam)
.ToArray<ContextParamValue>();
List<ContextParamValue> lst = cpvList
.Where(pv => d.Contains(new KeyValuePair<string, string>(pv.ContextParam.Name, pv.Value)))
//.Where(pv => true == true)
.ToList<ContextParamValue>();
Trace.TraceInformation("-- ParamValuesToList executed --");
return lst;
}
public List<ContextInstance> GetContextInstances(List<ContextParamValue> ContextParamValues, bool AsNoTracking = false)
{
if (!AsNoTracking)
return db.ContextInstances
.Include(x => x.ContextClass)
.Include(x => x.ContextParamValues.Select(p => p.ContextParam))
.Include(x => x.Documents)
.AsEnumerable<ContextInstance>() // <-- Allows boolean method as part of LINQ query
.Where(ci => IsSubset(ci.ContextParamValues, ContextParamValues))
.ToList<ContextInstance>();
else
return db.ContextInstances
.Include(x => x.ContextClass)
.Include(x => x.ContextParamValues.Select(p => p.ContextParam))
.Include(x => x.Documents)
.AsNoTracking()
.AsEnumerable<ContextInstance>()// <-- Allows boolean method as part of LINQ query
.Where(ci => IsSubset(ci.ContextParamValues, ContextParamValues))
.ToList<ContextInstance>();
}
public List<ContextInstance> GetContextInstances(string[] ParamNames, string[] ParamValues, bool AsNoTracking = false)
{
return GetContextInstances(ParamValuesToList(ParamNames, ParamValues), AsNoTracking);
}
}
Tuyên bố cụ thể từ các phương pháp trên được ném lỗi là
List<ContextParamValue> lst = cpvList
.Where(pv => d.Contains(new KeyValuePair<string, string>(pv.ContextParam.Name, pv.Value)))
.ToList<ContextParamValue>();
Trường hợp ngoại lệ tham chiếu null là KHÔNG ném dưới điều kiện sau đây:
- Có tồn tại, đối với một ContextInstance cụ thể, chỉ 1 ContextParamValue
- Ví dụ, ContextParamValue.ContextParam.Name = "ClientId" và ContextParamValue1.Value = "1"
Tham chiếu ngoại lệ vô được ném dưới điều kiện sau đây:
- Có tồn tại, đối với một ContextInstance cụ thể, hai hoặc nhiều ContextParamValues
- Ví dụ, ContextParamValue1.ContextParam.Name = "ClientId" và ContextParamValue1.Value = "1" PLUS ContextParamValue2.Co ntextParam.Name = "MotivationId" và ContextParamValue2.Value = "1".
tôi có thể xác nhận điều sau về phương pháp helper trong câu hỏi:
- d không phải là null cũng không chứa bất kỳ KeyValuePairs với null giá trị
- cpvList không phải là null và không có sản phẩm nào khi lỗi xảy ra.
- ContextParam không tải cho cha mẹ ContextParamValue thực thể trong mọi trường hợp (nó chỉ tải cho trường hợp ContextParamValue đầu tiên nhưng đối với các trường hợp tiếp theo chỉ có một giá trị null được nạp).
- Không có mục nhập ContextParam rỗng trong cơ sở dữ liệu ... Tất cả ContextParamValues có một mục nhập ContextParam.
Sau đây dấu vết và stacktrace thông tin được tạo ra trong thời gian chạy:
Ứng dụng: 2014-05-16T19: 00: 20 PID [4800] Lỗi System.NullReferenceException: Tham chiếu đối tượng không được đặt thành một thể hiện của một đối tượng. Ứng dụng: tại DocumentManagement.Helpers.RuntimeHelper. <> c__DisplayClass28.b__27 (ContextParamValue pv) trong c: \ Users \ xxx \ Dropbox \ xxx \ Active Dự án \ xxx \ DocumentManagement \ Helpers \ DocsHelper_RT.cs: dòng 229 Ứng dụng: tại System.Linq.Enumerable.WhereArrayIterator1. MoveNext() ứng dụng: ứng dụng tại System.Collections.Generic.List1..ctor (IEnumerable1 bộ sưu tập): tại System.Linq.Enumerable.ToList [TSource] (IEnumerable1 nguồn) ứng dụng: tại DocumentManagement.Helpers.RuntimeHelper .ParamValuesToList (Chuỗi [] ParamNames, String [] ParamValues) trong c: \ Users \ xxx \ Dropbox \ xxx \ Active Dự án \ xxx \ DocumentManagement \ Helpers \ DocsHelper_RT.cs: dòng 228 Ứng dụng: tại DocumentManagement.Helpers.RuntimeHelper.GetContextInstances (Chuỗi [] ParamNames, String [] ParamValues, Boolean AsNoTracking) trong c: \ Users \ xxx \ Dropbox \ xxx \ Active Dự án \ xxx \ DocumentManagement \ Helpers \ DocsHelper_RT.cs: dòng 262 Ứng dụng: tại xxx.Controllers.ClientController.LoadStep2 (Int64 ClientId, String Error) trong c: \ Users \ xxx \ Dropbox \ xxx \ Active Projects \ xxx \ xxx \ Views \ Client \ ClientController.cs: line 198
nếu "lst" không phải là null, không có nghĩa rằng truy vấn đầu tiên của bạn đã thành công? Nếu nó ném một ngoại lệ, "lst" sẽ không được chỉ định ở nơi đầu tiên. Bạn liệt kê truy vấn bằng cách gọi ToList() trên đó, do đó truy vấn sẽ được thực hiện thành công với "lst" được gán, hoặc ném một ngoại lệ, để lại "lst" chưa được gán. –
Để gỡ lỗi, tôi đề nghị bạn đặt biến vị ngữ của bạn từ mệnh đề Where trong một phương thức riêng biệt (chúng ta hãy gọi nó là "predicate") và thay đổi mệnh đề Where thành '.Where (predicate)'. Đặt một trình xử lý ngoại lệ trong phương thức dự đoán của bạn cho phép bạn thiết lập một điểm ngắt sẽ được kích hoạt khi một ngoại lệ xảy ra - điều này sẽ giúp bạn chẩn đoán nơi bạn có một giá trị null. Bởi vì, một điều dường như chắc chắn dựa trên lời giải thích của bạn: Truy vấn LINQ dường như giải quyết một tham chiếu null ở đâu đó ... – elgonzo
hiển thị stacktrace – Pawel