First statement did not work on dictionary result - c#

I have a method that returns a dictionary as:
public async Task<Dictionary<DateTime, double>> GetAvailableTimeOffWithExpiration(int userId)
{
..../ code here
Dictionary<DateTime, double> expirationDates = ...
return expirationDates;
}
Then I want to assign the first value of the dictionary to my DateTime variable of TimeOffApproved model as:
var timeOffWithExpiration = await this.GetAvailableTimeOffWithExpiration(u.Id);
var TimeOff = new TimeOffApproved()
{
ExpirationDate = timeOffWithExpiration.First()
};
But it is returning error:
Error CS0029: Cannot implicitly convert type
'System.Collections.Generic.KeyValuePair<System.DateTime, double>' to
'System.DateTime'
Why is trying to assign the dictionary if I'm using the First() statement?

The First() method returns the first element of a collection in case of the Dictionary that is a KeyPair Value. To get date part you need to add .Value or .Key (depending on the part you need - in your case .Key) to the statement like this:
var timeOffWithExpiration = await this.GetAvailableTimeOffWithExpiration(u.Id);
var TimeOff = new TimeOffApproved()
{
ExpirationDate = timeOffWithExpiration.First().Key
};
I would recommend a check to ensure that the first element is not null, like this for example (correction due to compiler error):
var timeOffWithExpiration = await this.GetAvailableTimeOffWithExpiration(u.Id);
if (timeOffWithExpiration != null)
{
var TimeOff = new TimeOffApproved()
{
ExpirationDate = timeOffWithExpiration.Any() ? timeOffWithExpiration.First().Key : new DateTime()
};
}

Related

Check if a List contains an object with a certain value using Nest ElasticSearch

I'm trying to build a filter to my BoolQuery.
the response object contians an object whic contains 2 properties, a bool and a list of another object like this :
responsObject : {
innerObject : {
myinnerObjectBoolProperty: Bool,
myinnerObjectListProperty : [
{
innerObjectType: myEnum,
// otherProperties
},
{
innerObjectType: myEnum,
// otherProperties
}
]
} ,
// other properties
}
I have a method that returns an IEnumerable<QueryContainer> to build a filter for a query
after i build the filters i assign them t a BoolQuery's Must BoolQuery bQuery property and I assign that BoolQuery to a SeachRequest's Query property and pass it to the ElasticClient's Search method
var searchRequest = new SearchRequest()
{
Query = bQuery,
// other assignments
};
var response = client.Search<responsObject >(searchRequest);
inside the method mentioned above the
filtering through the bool property is working fine like this:
if (filterValuesList.Contains("myBoolProperty", StringComparer.OrdinalIgnoreCase))
{
var termQuery = new TermQuery()
{
Field = "innerObject.myBoolProperty",
Value = "true"
};
queries.Add(termQuery);
}
but what i'm trying to do is to filter objects that have a certain vaule in myEnum.
var termQuery = new TermQuery()
{
Field = "innerObject.myinnerObjectListProperty.innerObjectType",
Value = "certainType"
};
but it doesn't work when I do it like that.
simply what I'm truing to achieve is an equivalent to this LINQ statment:
var result = responsObjects.Where(i =>i.innerObject.myinnerObjectListProperty.Any(p => p.innerObjectType == innerObjectType.CertainType));
I figured out what the problem was.
I had an attribute on myEnum property to convert the enum to string like : [JsonConverter(typeof(StringEnumConverter))]
so I thought that I should pass the string value of the enum.
I tried passing the underlying type of the enum (which is int) so it worked like a charm

MongoDB FilterDefinition and interfaces in C#

I have a MongoDB collection contains differents entity with same interface IDocument.
public class BarDocument: IDocument
{
public string BarField { get; set; }
}
Now I need to find inside this collection doing something like this:
var fooDoc = new FooDocument() { FooField = "test Foo Field" };
var barDoc = new BarDocument() { BarField = "test Bar Field" };
var barDoc1 = new BarDocument() { BarField = "test Bar Field 2" };
await _documentsCollection.InsertManyAsync(new List<IDocument>() { fooDoc, barDoc, barDoc1 });
var filterBar = Builders<BarDocument>.Filter.Where(x => x.BarField.Contains("Bar")) ;
var result = await _documentsCollection.Find(filterBar).ToListAsync();
But this Find statement ends in a compilation error:
Error CS1503 Argument 2: cannot convert from 'MongoDB.Driver.FilterDefinition<WebApi.Models.Entities.Documents.BarDocument>' to 'System.Linq.Expressions.Expression<System.Func<WebApi.Models.Entities.Documents.IDocument, bool>>'
Can someone give me a hint?
The _documentsCollection variable is defined as ICollection<IDocument>>, thus you can insert documents that are defined both as FooDocument and BarDocument and it works - MongoDB knows how to store them in one collection and preserve their original type (_t field).
Once they're inserted to the same collection, you're trying to query ICollection<IDocument>> using filter that is defined on the derived type, which won't be allowed by the compiler, since BarField is unknown to IDocument.
What you can do is to define another variable which targers BarDocument specifically and then run your query on such collection:
var barCollection = database.GetCollection<BarDocument>("yourcol");
var filterBar = Builders<BarDocument>.Filter.
Where(x => x.BarField.Contains("Bar"));
var result = await barCollection.Find(filterBar).ToListAsync();
This should work as long as your query returns only instances of BarDocument class.

How can I convert 'System.Collection.Generic.List<String>' into 'System.Windows.Documents.List'?

I have a table of doctors in my database. So I'm trying to get the list of the firstName of the doctors in my database.
In the ViewModel class I'm using this code to get it
public List DoctorsList ()
{
// string mainconn = Configuration
List ListOfDoctors;
using (var context = new GlabDbContext())
{
var result = (from c in context.Doctors
select c.LastName).ToList();
ListOfDoctors = result;
}
return ListOfDoctors;
}
I want to use this function like a method of my ViewModel class an it will have a return.
But I'm getting an error saying that:
Impossible to convert implicitely 'System.Collections.Generic.List into 'System.Windows.Documents.List'?
I try to cast the result like this
public List DoctorsList ()
{
// string mainconn = Configuration
List ListOfDoctors;
using (var context = new GlabDbContext())
{
var result = (from c in context.Doctors
select c.LastName).ToList();
**ListOfDoctors = (list)result;**
}
return ListOfDoctors;
}
but I get an error at the run time for the app.
How can I resolve the problem?
Your List ListOfDoctors appears to be really an
System.Windows.Documents.List ListOfDoctors;
and this is also the return type of your method.
Your var result really is
System.Collections.Generic.List<string> result
The two types are not compatible, meaning that you cannot cast one to the other (as the error message says).
I suspect you don't really want to return a Documents.List but a List<string> (containing just those names). So:
Remove a using System.Windows.Documents; from your file
Change all List to List<string>
You can try this like this:
System.Windows.Documents.List listx = new System.Windows.Documents.List();
foreach (var r in result)
{
listx.ListItems.Add(new ListItem(new Paragraph(new Run(r)));
}
Most probably you had an intention to use the IList or List<T>, but accidentally imported the System.Windows.Documents.List and all the later errors appeared because of that.
Please, take a moment and think what return type do you really need and if you want to return a collection of string elements then either use List<string> or IList as a return type:
public IList DoctorsList() // or return List<string> or IList<string> (generic version)
{
// string mainconn = Configuration
IList ListOfDoctors;
using (var context = new GlabDbContext())
{
var result = (from c in context.Doctors
select c.LastName).ToList();
ListOfDoctors = result;
}
return ListOfDoctors;
}
Shorter version (c# 8 compatable):
public IList DoctorsList() // or return List<string> or IList<string> (generic version)
{
using var context = new GlabDbContext();
return (from c in context.Doctors select c.LastName).ToList();
}
Remember:
You can do casting only with compatible types, which means that there should be either appropriate conversion operators defined for both types or a BaseāŸ¶Derived class relationship should exist between types.
For more information:
About Casting and type conversions read here.
About Type conversion operators read here.

Handle null element in linq

I'm reading data from an XML. I'm running into an issue where a value is null and I'm not sure the best way to handle it. Below is a snippet of code. The Street Address 2 does not exist in this XML but does in others so I need to make it dynamic enough to handle both instances.
var storeInfo = storeRows.Descendants("Store").Select(s => new
{
storeName = s.Element("StoreName").Value,
streetAddress1 = s.Element("StreetAddress1").Value,
streetAddress2 = s.Element("StreetAddress2").Value
});
{
foreach (var st in storeInfo)
{
alStoreName.Add(st.storeName.ToString());
alStreet1.Add(st.StreetAddress1.ToString());
alStreet2.Add(st.StreetAddress2.ToString());
}
}
Use explicit cast instead of accessing Value property
var storeInfo = storeRows.Descendants("Store").Select(s => new
{
storeName = (string)s.Element("StoreName"),
streetAddress1 = (string)s.Element("StreetAddress1"),
streetAddress2 = (string)s.Element("StreetAddress2")
});
This will return null if the element does not exist.
In addition I recommend you to create a class to encapsualate store info instead of storing information in different lists. Then just have a list of storeInfo's instead of a list of anonymous type:
var storeInfo = storeRows.Descendants("Store").Select(s => new StoreInfo
{
storeName = (string)s.Element("StoreName"),
streetAddress1 = (string)s.Element("StreetAddress1"),
streetAddress2 = (string)s.Element("StreetAddress2")
});
You should use (string)XElement explicit cast instead of Value property. It will return null when element doesn't exist.
streetAddress2 = (string)s.Element("StreetAddress2")
You can cast XElement to most of the primitive types, string, DateTime, Guid and Nullable<T> of above. See full list here: XElement Type Conversions
The same rule applies to XAttribute.

async and anonymous types

This method:
private async Task readFileInfo(string folderId)
Has a call to another method:
importCount = await VM.importVehicles(myXDoc);
Defined here: (note: I changed it from a for loop to a for each but I'm getting similar results).
public async Task<Int32> importVehicles(XDocument importXMLDocument)
{
var Importedvehicles = from vehicle in importXMLDocument.Descendants("vehicle")
select new
{
VehicleName = vehicle.Element("VehicleName").Value,
VehicleYear = vehicle.Element("VehicleYear").Value,
Odometer = vehicle.Element("Odometer").Value,
LicensePlate = vehicle.Element("LicensePlate").Value,
OilWeight = vehicle.Element("OilWeight").Value,
OilQuantity = vehicle.Element("OilQuantity").Value,
OilFilterModelNumber = vehicle.Element("OilFilterModelNumber"),
AirFilterModelNumber = vehicle.Element("AirFilterModelNumber"),
OilChangedDate = vehicle.Element("OilChangedDate"),
OilChangedOdometer = vehicle.Element("OilChangedOdometer"),
NextOilChangeDate = vehicle.Element("NextOilChangeDate"),
NextOilChangeOdometer = vehicle.Element("NextOilChangeOdometer"),
SettingDistance = vehicle.Element("SettingDistance"),
SettingMonths = vehicle.Element("SettingMonths"),
};
Int32 vehicleId;
vehicleId = await getMaxVehicleId();
try
{
foreach (var item in Importedvehicles)
{
vehicle myImportedVehicle = new vehicle();
myImportedVehicle.VehicleId = vehicleId += 1;
myImportedVehicle.ImagePath = "Assets/car2.png";
myImportedVehicle.VehicleName = item.VehicleName;
myImportedVehicle.VehicleModel = item.VehicleName;
myImportedVehicle.VehicleYear = short.Parse(item.VehicleYear);
myImportedVehicle.CurrentOdometer = Convert.ToInt32(item.Odometer);
myImportedVehicle.LicensePlate = item.LicensePlate;
myImportedVehicle.LastOilChangedDate = Convert.ToDateTime(item.OilChangedDate.Value.ToString()).ToString("d");
myImportedVehicle.LastOilChangedOdometer = (Int32)item.OilChangedOdometer;
myImportedVehicle.ReminderDistance = (Int32)item.SettingDistance;
myImportedVehicle.ReminderMonths = (Int32)item.SettingMonths;
vehicleInformation myImportVI = new vehicleInformation();
myImportVI.OilWeight = item.OilWeight;
myImportVI.OilAmount = item.OilQuantity;
myImportVI.OilFilterNumber = item.OilFilterModelNumber.Value.ToString();
myImportVI.AirFilterNumber = item.AirFilterModelNumber.Value.ToString();
myImportedVehicle.vehicleInfo = myImportVI;
m_vehicles.Add(myImportedVehicle);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message.ToString());
}
await SaveList();
return Importedvehicles.Count();
}
I'm getting an error:
Object reference not set to an instance of an object.
when I step through it the iVehicle is highlighted but then it goes directly to the for statement. Then it errors as it looks as it hasn't gotten the results from iVehicle yet.
This doesn't 100% answer your question, but it should give you a good start.
The reason the debugger jumps straight into the for...loop after the declaration of iVehicle, is because your query does not get executed when you declare it. Therefore, iVehicle at that point is not a collection of anonymous types.
When you call .Count(), the query is being executed and iVehicle is attempting to be turned into a proper collection of anonymous types. However, because something in the query (that is being executed after you call .Count()) is null, you're receiving an NullReferenceException.
You should start by verifying that both importXMLDocument and the return value from the call to Descendants() is not null.
Hope that helps anyway.
EDIT:
Now that you've given a complete example, you have heaps of places that could potentially be null.
Each time you use this:
vehicle.Element("SomeElementNameHere")
That could potentially be null. Then you're calling the .Value property on a null object.
You need to make sure each element is definitely there. Isolate each case, and determine which one is null.
Try writing your code like this:
var query =
from vehicle in importXMLDocument.Descendants("vehicle")
select new { ... };
var iVehicle = query.ToArray();
for (var i = 0; i <= iVehicle.Count(); i++)
{
...
}
You need to force the evaluation of the query. That's what the .ToArray is doing. The query itself is only the definition of the query, not the results.

Categories

Resources