I've created a new Entity Object:
mplToCreate = this._context.MasterPartsList.CreateOBject();
then, I want to set the parentPnID to an existing item's property that I tried querying for using the following IQueryable expression:
mplToCreate.parentPnID = this._context.MasterPartNumbers.FirstOrDefault(x => x.pn == this._selectedItem.Pn).pnID;
But I get a NullReferenceException at that line. (I know that there exists a pnID in MasterPartNumbers that matches this logic.)
Please help me correct my right-hand expression so that I can set the property accordingly.
Is this a typo, or is it the problem?
// assignment
FirstOrDefault(x => x.pn = this._selectedItem.Pn)
// equality
FirstOrDefault(x => x.pn == this._selectedItem.Pn)
Related
i am using viewmodel to display data from two tables (Eta and Voyage) and i have used viewmodel name as 'EtaVoyage'.The problem is when i use this query, it gives me this error
Additional information: Object reference not set to an instance of an object.
var Test = db.Etas.AsEnumerable().Select(v => new EtaVoyage()
{
ShippingAgent = v.ShippingAgent,
VesselInformation = v.VesselInformation,
Port = v.Port,
CPort = v.CPort,
EtaDate = v.EtaDate,
GoodsCarried = v.VoyageDetails.FirstOrDefault().GoodsCarried,
VoyagePurpose = v.VoyageDetails.FirstOrDefault().VoyagePurpose
}).ToList();
return View(Test);
But when i comment the last two fields related to voyagedetails, it is working fine.
var Test = db.Etas.AsEnumerable().Select(v => new EtaVoyage()
{
ShippingAgent = v.ShippingAgent,
VesselInformation = v.VesselInformation,
Port = v.Port,
CustomPort = v.CustomPort,
EtaDate = v.EtaDate,
// GoodsCarried = v.VoyageDetails.FirstOrDefault().GoodsCarried,
// VoyagePurpose = v.VoyageDetails.FirstOrDefault().VoyagePurpose
}).ToList();
return View(Test);
i need to display these two columns too in the index page.
FirstOrDefault() might return null,
Enumerable.FirstOrDefault : Return Value
Type: TSource
default(TSource) if source is empty; otherwise, the first element in source.
Use
.Select(i=>i.GoodsCarried).FirstOrDefault()
....
GoodsCarried = v.VoyageDetails.Select(i=>i.GoodsCarried).FirstOrDefault(),
VoyagePurpose = v.VoyageDetails.Select(i=>i.VoyagePurpose).FirstOrDefault()
}).ToList();
The collection v.VoyageDetails must not contain any items, and therefore FirstOrDefault is returning the default (null for reference types). You can handle this special case separately, or, since you seem to just be flattening a collection, you can use a null-conditional operator to set GoodsCarried and VoyagePurpose to null when FirstOrDefault returns null.
GoodsCarried = v.VoyageDetails.FirstOrDefault()?.GoodsCarried,
VoyagePurpose = v.VoyageDetails.FirstOrDefault()?.VoyagePurpose
Note it is also possible that:
v.VoyageDetails itself is null, depending on how your class is initialized and data is loaded. If this is expected, you may need to handle this case as well. Again with the null-conditional operator:
GoodsCarried = v.VoyageDetails?.FirstOrDefault()?.GoodsCarried,
VoyagePurpose = v.VoyageDetails?.FirstOrDefault()?.VoyagePurpose
If you are using an ORM such as Entity Framework, the VoyageDetails collection is not eagerly loaded, it may simply not be retrieving the data for you. If this applies, you need to explicitly load the data in the collection. In Entity Framework this is done with an Include call. Note your AsEnumerable() call will stop Linq-To-Sql from optimizing this into a single query, but I assume this is intentional:
db.Etas.Include(x => x.VoyageDetails).AsEnumerable().Select(...)
I am trying to access a user object in a collection with the id = to users101 and set this to another users.
Controller.MyObject.SingleOrDefault(x => x.Id == "user101") = OtherUser();
Thanks in advance.
You can't do it with one LINQ expression.
Usually LINQ extensions works on enumerables, if MyObject is a collection you first have to find the required item and then overwrite it with the new object (moreover SingleOrDefault() will simply return null if condition is not satisfied).
You should write something like this (exact code depends on what MyObject is):
var item = Controller.MyObject.SingleOrDefault(x => x.Id == "user101");
if (item != null)
Controller.MyObject[Controller.MyObject.IndexOf(item)] = new OtherUser();
Please note that if you do not really need the check performed by SingleOrDefault() you can simplify the code (and avoid the double search performed in SingleOrDefault() and IndexOf()).
If this is "performance critical" maybe it is better to write an ad-hoc implementation that does this task in one single pass.
Try it in two lines:
var objectWithId = Controller.MyObject.SingleOrDefault(x => x.Id == "user101");
(objectWithId as WhateverTypeOfObjectOtherUserIs) = OtherUser();
private string FindTaxItemLocation(string taxItemDescription)
{
if (!templateDS.Tables.Contains(cityStateTaxesTable.TableName))
throw new Exception("The schema dos not include city state employee/employer taxes table");
var cityStateTaxes =
templateDS.Tables[cityStateTaxesTable.TableName].AsEnumerable().FirstOrDefault(
x => x.Field<string>(Fields.Description.Name) == taxItemDescription);//[x.Field<string>(Fields.SteStateCodeKey.Name)]);
if (cityStateTaxes != null)
return cityStateTaxes[Fields.SteStateCodeKey.Name].ToString();
return null;
}
cityStateTaxes is a DataRow, why/how I cannot get the column value inside FirstOrDefault()?
Thanks,
FirstOrDefault() selects the first item in the collection (optionally that satisfies a predicate) or returns null in the case there it is empty (or nothing satisfies the predicate). It will not do projections for you. So if you use it, it can be awkward to access a field of the item since you must include default value checks.
My suggestion is to always project to your desired field(s) first before using FirstOrDefault(), that way you get your field straight without needing to perform the check.
var cityStateTaxes = templateDS.Tables[cityStateTaxesTable.TableName]
.AsEnumerable()
.Where(row => row.Field<string>(Fields.Description.Name) == taxItemDescription) // filter the rows
.Select(row => row.Field<string>(Fields.SteStateCodeKey.Name)) // project to your field
.FirstOrDefault(); // you now have your property (or the default value)
return cityStateTaxes;
I'm trying to use an already existing Expression building class that I made when trying to do a select clause, but I'm not sure how to attach the expression to the expression tree for the Select, I tried doing the following:
var catalogs = matchingCatalogs.Select(c => new
{
c.CatalogID,
Name = EntitiesExpressionHelper.MakeTranslationExpression<Catalog>("Name", ApplicationContext.Instance.CurrentLanguageID).Compile().Invoke(c),
CategoryName = EntitiesExpressionHelper.MakeTranslationExpression<Category>("Name", ApplicationContext.Instance.CurrentLanguageID).Compile().Invoke(c.Category),
c.CategoryID,
c.StartDateUTC,
c.EndDateUTC
});
But I obviously get the error stating that the Entity Framework can't map Invoke to a SQL method. Is there a way to work around this?
FYI, EntitiesExpressionHelper.MakeTranslationExpression<T>(string name, int languageID) is equivalent to:
x => x.Translations.Count(t => t.LanguageID == languageID) == 0 ? x.Translations.Count() > 0 ? x.Translations.FirstOrDefault().Name : "" : x.Translations.FirstOrDefault(t => t.LanguageID == languageID).Name
EDIT: I realize that I need to use an ExpressionVisitor to accomplish this, but I'm not sure how to use an ExpressionVisitor to alter the MemberInitExpression, so if anyone knows how to accomplish this, let me know.
You need to capture the expressions in vars. You won't be able to use anonymous types. The general idea is that this works:
Expression<Func<Foo, Bar>> exp = GenExpression();
var q = matchingCatalogs.Select(exp);
But this will not:
var q = matchingCatalogs.Select(GenExpression());
The first happily passes the result of GenExpression to L2E. The second tries to pass GenExpression itself to L2E, rather than the result.
So you need a reference to a var of the same type as the expression. Those can't be implicitly typed, so you'll need a real type for your result type.
I have an issue using the Dynamic Expression API. I cannot seem to compare a DataTable field against DBNull.Value. The API is supposed to be able to "support static field or static property access. Any public field or property can be accessed.". However given the following query:
var whatever = table1.AsEnumerable()
.Join(table2.AsEnumerable(),
(x) => x.Field<int>("Table1_ID"),
(y) => y.Field<int>("Table2_ID"),
(x, y) => new { x, y})
.AsQueryable()
.Where("x[\"NullableIntColumnName\"] == DBNull.Value");
I end up getting the error: "No property or field 'DBNull' exists in type '<>f__AnonymousType0`2'"
Anyone have ideas on how to get around this? I can't use Submission.Field("NullableIntColumnName") in the string passed to the Where method either, btw, or else I would be able to compare against null instead of DBNull.Value.
Well, I finally got it. cptScarlet almost had it.
var values = new object[] { DBNull.Value };
...
.Where("x[\"NullableIntColumnName\"] == #0", values);
or
.Where("x[\"NullableIntColumnName\"] == #0", DBNull.Value);
What happens when you replace your current .Where with something like
.Where(string.format("x[\"NullableIntColumnName\"] == {0}",DBNull.Value));
If you change x.Field<int>("Table1_ID") to x.Field<int?>("Table1_ID") then you'll get nullable integers instead of regular integers, and any DBNull values will be converted to simple C# null values. Based simply on your code snippet, I'm not even sure you'd need dynamic expressions - a simple .Where(foo => foo.x == null) ought to work.
In general, you can also try:
.Where("NullableColumnName.HasValue");
Sorry to non-answer with a USL but...
Have you looked in the source? There's not a lot of it. My guess is that DBNull is not in the list of registered root objects.
I dont have the source to hand right now, but it is also likely to tell you what any other constants one might compare against might be.
.Where(a => a.IntColName == null);
Edit:
Sorry, I did't see this dynamic requirement... Dynamic would be: (at least in Framework 4)
var intColName = "...";
.Where(string.Format("it.{0} is null", intColName));