c# MVC XML Record Value - c#

I have an xml file:
<profiles>
<profile username="user4" fullname="Full Name" />
</profiles>
I am trying to retrive the value of the fullname, here is what I tried:
public List<string> GetFullName(string username)
{
List<Profile> list = null;
try
{
list = (from t in ProfileList
where t.UserName == username
select t).FirstOrDefault();
}
catch { }
List<string> userFullName = new List<string>();
if (list != null)
{
foreach (Profile t in list)
{
userFullName.Find(t.FullName);
}
}
return userFullName;
}
FirstOrDefault gives an error!
Thanks in advance.

FirstOrDefault() is an extension method, which means that it's basically similar in concept to doing something like
var myList = new List<int>() { };
int myValue = StaticUtilsClass.FirstOrDefault(myList);
Now, if you look at FirstOrDefault documentation, notice that it throws a null argument exception when you pass in a null parameter.
What this means is that
List<int> myList = null;
myList.FirstOrDefault();
will throw an exception.
So, anytime you call x.FirstOrDefault(), and encounter a problem (i.e. an "error") the first thing to check is whether x, in this case, your query, is returning null.
From there, I would take a look at the fact that FirstOrDefault() is going to return a single entity, but you're setting it equal to a List<Profile>. Unless your ProfileList is an enumeration of List<Profile>, that's going to be a problem as well.
That should get you started anyway. Beyond that, it'd be helpful to know what ProfileList is and where it's declared.

I'd rather rewrite your code like this
public String GetFullName(string username)
{
var targetObject = (from t in ProfileList
where t.UserName == username
select t).FirstOrDefault();
if (targetObject != null) return targetObject.FullName;
throw new Exception("Target user is not found");
}

Related

How to assign value to class instance members using the instance name in a select method

I have this method:
public DemographicData GetDemographicByZipCode(string zipcode)
{
DemographicData demoData = new DemographicData();
using(var context = new DataContext())
{
var result = from item in context.Demographic
where item.ZipCode == zipcode
select item;
foreach (var data in result)
{
demoData.City = data.City;
demoData.State = data.State;
demoData.Zip = data.ZipCode;
}
}
return demoData;
}
I am attempting to write the method without the loop as indicated below but as apparent, it will not work because I cannot use an assignment operator within the expression tree.
public DemographicData GetDemographicByZipCode(string zipcode)
{
DemographicData demoData = null;
// Instantiate to new instance in the select method.
// I need to use this instance demoData
using(var context = new DataContext())
{
var result = from item in context.Demographic
where item.ZipCode == zipcode
select new DemographicData()
{
//assign data to instance member here.
};
}
return demoData;
}
No, you can't do that. But if your goal is for demoData to represent a single result from your query, then you can do something like this:
public DemographicData GetDemographicByZipCode(string zipcode)
{
DemographicData demoData = null;
using(var context = new DataContext())
{
demoData = (from item in context.Demographic
where item.ZipCode == zipcode
select new DemographicData()
{
Zip = item.ZipCode,
City = item.City,
State = item.State
}).FirstOrDefault();
}
//Do other stuff to demoData here, if needed
return demoData;
}
That uses FirstOrDefault to get the first one in the list (or null if there are none). In the loop in your example, you're just overwriting the values, so I assume you are only expecting one result.
Update: If you are expecting more than one result, then return IEnumerable<DemographicData>, like this:
public IEnumerable<DemographicData> GetDemographicByZipCode(string zipcode)
{
List<DemographicData> demoData = null;
using(var context = new DataContext())
{
demoData = (from item in context.Demographic
where item.ZipCode == zipcode
select new DemographicData()
{
Zip = item.ZipCode,
City = item.City,
State = item.State
}).ToList();
}
//Do other stuff to demoData here, if needed
return demoData;
}
Use List<DemographicData> and ToList() inside the method to force it to actually perform the query there. If you don't use ToList(), it will perform the query when the list is first accessed, which will be outside of the using, when your context is disposed. It might also complain about multiple enumerations, depending on your code.
try:
var result = from item in context.Demographic
where item.ZipCode == zipcode
select item;
This will work.
City = item.City,
State = item.State,
Zip = item.ZipCode
What is still wrong with your code is that you are returning single DemographicData object whereas result will be collection of DemographicData objects even if there is only one that fulfills the condition tem.ZipCode == zipcode.
If you are expecting only exactly one instance of DemographicData do it this way
var result = (from item in context.Demographic
.
(your query here)
.
).Single();
If you are expecting one or zero then replace Single() with FirstOrDefault(). If you are expecting a collection then the return type of that method should be IEnumerable<DemographicData> or IQueryable<DemographicData> or any other that suits you best. If you need list/ array then replace Single() with ToList()/ToArray().

C# Linq Registry values to DataTable

I am trying to enumerate the registry to fetch a list of installed applications and return them via Linq to a DataTable in C#.
I have tried various things including sanitizing it as XML (which worked), however it seemed rather inefficient as ultimately, i require this as DataTable object.
Here is where i am at currently:
//Warning
public static DataRow DataRowInstalledApplication (this RegistryKey rgkey, string keyName)
{
RegistryKey key = rgkey.OpenSubKey(keyName, false);
try
{
//Application Name is mandetory for a given key.
if (key == null|| key.RegToString("DisplayName", false) == null )return null;
//Build a sanitised data row
var rowBuilder = new DataTable().NewRow();
rowBuilder["DisplayName"] = key.RegToString("DisplayName");
rowBuilder["UninstallString"] = key.RegToString("UninstallString");
rowBuilder["InstallLocation"] = key.RegToString("InstallLocation");
rowBuilder["Publisher"] = key.RegToString("Publisher");
rowBuilder["DisplayIcon"] = key.RegToString("DisplayIcon");
return rowBuilder;
}
finally
{
if (key != null) key.Close();
}
}
Here is the method that contains the Linq:
public DataTable GetRegistryApplicationDataTable(RegistryKey registryKey, string tableName)
{
if (registryKey != null)
{
try
{
//change to throw non critical error
var installedListXml = new DataTable(tableName, from name in registryKey.GetSubKeyNames()
let app = registryKey.DataRowInstalledApplication(name)
select app);
return installedListXml;
}
catch
{
return new DataTable(tableName);
}
finally
{
registryKey.Close();
}
}
return null;
}
The main problem i have is that i do not really understand Linq very well. Mainly how individual values are used during the iteration to call other things similar to
foreach (string value in collection)
{
Somefunction(value);
}
, in the case of the registry values i am trying to retrieve, i do not understand how to make a Linq query pass each key name to function, which will generate a row and the Linq Query return as a data table.
I would be grateful of any pointers! thanks
ps i call the above with
private static readonly RegistryKey HKLMUninstallKey = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
GetRegistryApplicationDataTable(HKLMUninstallKey, "Computer")
and expect back a data table called computer.
Your first problem is your linq statement. You are trying to pass an IEnumerable into a constructor that is expecting either a (string) or a (string, string). If you modify your logic to this:
var query = from name in registryKey.GetSubKeyNames()
let app = registryKey.DataRowInstalledApplication(name)
select app;
foreach(var result in query)
{
var installedListXml = new DataTable(tableName, result);
}
That would work IF result was actually a string, but it's a DataRow, which is not a valid parameter for a DataTable constructor. Instead, there is an extension method you can call on the resulting query to copy to a data table, like so:
var query = from name in registryKey.GetSubKeyNames()
let app = registryKey.DataRowInstalledApplication(name)
select app;
var installedListXml = query.CopyToDataTable();
When you write a LINQ query statement, it is not executed until you try to enumerate over the results. CopyToDataTable does this, so if you were to step through your code you will notice that your function DataRowInstalledApplication will not be called until you call CopyToDataTable and not when you first assign query. The result you receive is an Enumerator that you can treat just like any other, whether that's using in a foreach loop or calling ToList or so forth. Inside the linq query itself, you are actually iterating over other values, in this case GetSubKeyNames. It would be functionally equivalent if you were to do this instead:
var dataRows = new List<DataRow>();
foreach(var name in registryKey.GetSubKeyNames())
{
dataRows.Add(registryKey.DataRowInstalledApplication(name));
}
return dataRows.CopyToDataTable();

Datatable Comparison of - primary keys is not working

I have written a code block which Compares datatable for Scheme differences.
this is the code:
private static void ValidateSchema(DataTable originalTbl, DataTable otherTbl)
{
var primaryKeyDoesNotMatch = originalTbl.PrimaryKey != otherTbl.PrimaryKey;
if(primaryKeyDoesNotMatch)
{
throw new ArgumentException("primary key does not match");
}
var primaryKeyDoesNotExist = originalTbl.PrimaryKey == null;
if(primaryKeyDoesNotExist)
{
throw new ArgumentException("primary key does not exist");
}
var otherTableHasAdditionalColumns = (from x in otherTbl.Columns.OfType<DataColumn>() where !originalTbl.Columns.OfType<DataColumn>().Any(y => y.ColumnName == x.ColumnName) select x).Any();
if (otherTableHasAdditionalColumns)
{
throw new ArgumentException("Other table does have additional columns.");
}
var columnsAreMissingInOtherTable = (from x in originalTbl.Columns.OfType<DataColumn>() where !otherTbl.Columns.OfType<DataColumn>().Any(y => y.ColumnName == x.ColumnName) select x).Any();
if (columnsAreMissingInOtherTable)
{
throw new ArgumentException("Other table does not have all the columns.");
}
var columnDataTypesDoesNotMatch = (from x in otherTbl.Columns.OfType<DataColumn>() where originalTbl.Columns.OfType<DataColumn>().Any(y => x.DataType != y.DataType) select x).Any();
if (columnDataTypesDoesNotMatch)
{
throw new ArgumentException("Column's data type does not match");
}
}
I also have a Unit test for this which has been implemented to test all these scenarios.
the problem is that even when i test the "columnDataTypeDoesNotMatch" or "columnsAreMissinginOtherTable" it runs till the first IF statement and tells me "primary key does not match" however they do!
any idea why this happens?
your help is appreciated
tanx in advance.
Sure. The PrimaryKey can never equal one another (well, unless it's the same table, or they both have null - although it should still have two separate new DataColumn[0] arrays), because you're performing a reference comparison, and over an array to boot.
Instead, you have to check for example based on the names of the columns involved (and depending on your requirements, data types as well):
bool Compare(DataColumn[] primary, DataColumn[] secondary)
{
if (primary.Length != secondary.Length) return false;
var names = new HashSet<string>(secondary.Select(col => col.ColumnName));
return primary.All(col => names.Contains(col.ColumnName));
}
You'll have to expand those as required per your requirements, for example based on whether you care about case sensitivity etc.

Should my query return null when it doesn't find any items?

I have a multiselectlist where a user can pick some or none inputvoltages. When the user selects no InputVoltages my query throws a null exception when I call .Tolist(). Why am I not just getting back an empty list?
I'm using MVC5 C# and entity framework 6.
repository
public IQueryable<InputVoltage> All
{
get { return context.InputVoltages; }
}
controller
var newInputVoltages = unitOfWorkPds.InputVoltageRepository
.All.Where(m => engineeringPdsEditViewModel.SelectedInputVoltages
.Contains(m.Id))
.ToList<InputVoltage>();
All does return a list but SelectedInputVoltages is null when nothing is selected. I was wondering if that was the issue.
When I use this query and add a where statement for my index page I don't receive a null error when I call ToList
IQueryable<EngineeringPdsIndexViewModel> query =
(from a in context.EngineeringPds
select new EngineeringPdsIndexViewModel
{
Id = a.Id,
Name = a.Name,
Status = a.Status,
AnnualQuantities = a.AnnualQuantities,
ToMarketDate = a.ToMarketDate,
SubmittedBy = a.SubmittedBy,
TargetPrice = a.TargetPrice
});
So I believe Brian has the right idea of what is wrong but here is the issue extended
I have a multiselect box that is populated in the get action method by
IList<InputVoltage> inputVoltagesList = unitOfWorkPds.InputVoltageRepository.All.ToList();
then
pdsEditViewModel.InputVoltageList = inputVoltagesList.Select(m => new SelectListItem { Text = m.Name, Value = m.Id.ToString() }); in my view I hav#Html.ListBoxFor(m => m.SelectedApprovals, Model.ApprovalList)
but when a user makes no selections the selectedInputvoltages comes into my post controller action as null how do I get it to come in as an empty list?
UPDATE
For anyone who runs into the same problem Brians first answer explains the issue. The work around for submitting a ListBox with empty lists can be found here
How can I return an empty list instead of a null list from a ListBoxFor selection box in Asp.net MVC?
Any Extension method defined in the BCL for IEnumerable<T> or IQueryable<T> that returns IEnumerable<T> or IQueryable<T> will not return null. It might return an empty collection, but that is very different to null.
try this:
var newInputVoltages = engineeringPdsEditViewModel.SelectedInputVoltages == null ?
unitOfWorkPds.InputVoltageRepository.All :
unitOfWorkPds.InputVoltageRepository.All.Where(m => engineeringPdsEditViewModel.SelectedInputVoltages.Contains(m.Id)).ToList();
Where will not return null. The problem is in the argument:
engineeringPdsEditViewModel.SelectedInputVoltages.Contains(m.Id)
A NULL engineeringPdsEditViewModel or SelectedInputVoltages can cause NullReferenceException to be thrown. So you need to do a null check against these objects.
You can see this play out with a similar test sample. Here we get a nullrefex because myString is null. So when Where executes it tries to do a comparison and blows up:
var test = new TestClass(1);
var test2 = new TestClass(2);
var test3 = new TestClass(3);
List<TestClass> tests = new List<TestClass>();
tests.Add(test);
tests.Add(test2);
tests.Add(test3);
string myString = null;
var result = tests.Where(t => myString.Contains(t.Myint.ToString())).ToList();
Console.WriteLine(result.Count);
Update: (To answer your comment)
You can return an empty list like this:
List<InputVoltage> newInputVoltages = new List<InputVoltage>();
if(engineeringPdsEditViewModel != null && engineeringPdsEditViewModel.SelectedInputVoltages != null)
{
//Where params are not null so its safe to use them
newInputVoltages = unitOfWorkPds.InputVoltageRepository
.All.Where(m => engineeringPdsEditViewModel.SelectedInputVoltages
.Contains(m.Id))
.ToList<InputVoltage>();
}
//else no need to do anything...just return the empty list created above
return newInputVoltages;
you will not get an empty list and it's expected behaviour it returns null.
just test the input (I used the Ternary Operator) when you create the variable and you won't need any validation later
var newInputVoltages = SelectedInputVoltages.Any()
? unitOfWorkPds.InputVoltageRepository
.All.Where(m => engineeringPdsEditViewModel.SelectedInputVoltages.Contains(m.Id))
.ToList<InputVoltage>()
: new List<InputVoltage>();

Sorting an IList

I have got a complete list of my brands to appear in my DropDownBox, however there appears to be no order (simply how they are input into the database) and I need to sort them into alphabetical order.
But it doesn't look like I can use the .Sort(); on an IList and there doesn't seem to be anything similar on ILists so I am at a bit of a loss, I have tried to convert the IList into a List and then using the List.Sort() method but I have had no luck with this as it just comes back unsorted again:
public void BrandListRetrieve()
{
var factory = new BrandFactory();
var customBool1State =
factory.ByCustomBoolean1(false, CoreHttpModule.Session);
if (customBool1State != null)
{
var brandDropDown = CoreHttpModule
.Session
.CreateCriteria(typeof(Brand)).List<Brand>();
foreach (Brand brand in brandDropDown)
{
this.Items.Add(brand.Name);
}
if (this.Items.Count < 0)
{
this.Items.Insert(0, new ListItem("Hello World", "Hello World"));
}
var brandList = brandDropDown as List<string>;
if (brandList != null)
brandList.Sort();
}
}
you should try this;
foreach (Brand brand in brandDropDown.OrderBy(b => b.Name))
You can certainly REMOVE the following lines from your code;
var brandList = brandDropDown as List<string>;
if (brandList != null)
brandList.Sort();
it seems that you need to use brand.Sort() with Compare method. Try to read this manual http://msdn.microsoft.com/en-us/library/w56d4y5z.aspx

Categories