First, let me tell you what error I am getting.
'DDLTesttoAppear' has a SelectedIndex which is invalid because it
does not exist in the list of items. Parameter name: value
I have many enums in my project, Here two enums are related two this question.
This Two enums are
public enum Gender
{
NA = 0, Male = 1, Female = 2
}
and
public enum NumberOfAdmissionTest
{
NA = 0, First = 1, Second = 2, Third = 3, Fourth =4
}
In UI page I have two DDls they are like
DDLGender.DataSource = Enum.GetNames(typeof(Gender));
DDLGender.DataBind();
DDLTestApearnce.DataSource = Enum.GetNames(typeof(NumberOfAdmissionTest));
DDLTestApearnce.DataBind();
This fields can be inserted as null into the database. Therefore, while returning the record I am using a null hander function
where the line of code to execute is that
candidateEntity.CandidateGender = nullHandler.GetInt32(CANDIDATE_GENDER);
candidateEntity.TestToAppear = nullHandler.GetInt32(TEST_TO_APPEAR);
public int GetInt32(String sFieldName)
{
return (_reader[sFieldName] == DBNull.Value) ? 0 : _reader.GetInt32(_reader.GetOrdinal(sFieldName));
}
After retrieving the record, I am binding this with two ddls like
DDLGender.SelectedIndex = candidateEntity.CandidateGender;
DDLTesttoAppear.SelectedIndex = candidateEntity.TestToAppear;
Now, the interesting or confusing, whatever you say, part of this problem is that for gender, it's not generating any error, but for test appearance it's generating the error.
You are binding DDLTestApearnce in your sample, but are getting the error (and setting the selected value) on DDLTesttoAppear.
Related
The user must enter the name of the student and then enter the number of faults he has (the numFaltas column)
How do I change only the numFalts column and keep the rest?
Sorry for English. I'm learning yet.
Thank you!
My list:
alunosMatriculados.Add(new Aluno
{
matAluno = 1,
nomeAluno = "THIAGO BUARQUE",
cpfAluno = "111.111.111-11",
turmaAluno = "3H",
numFaltas = 4
});
alunosMatriculados.Add(new Aluno
{
matAluno = 2,
nomeAluno = "MARIANA DA SILVA",
cpfAluno = "111.111.111-12",
turmaAluno = "2I",
numFaltas = 0
});
You can do something like this:
if (alunosMatriculados.Any(a => a.nomeAluno == inputName))
alunosMatriculados.Where(a => a.nomeAluno == inputName).ToList().ForEach(a =>a.numFaltas = inputFaults);
But be careful because if there's more than one student with the same name you will change the faults for all of them. It would be better to make sure that the names are unique or use an unique field like an ID (maybe your matAluno)
You can do this in simple way by using foreach loop
You first verify that If your inputName parameter is null or not
Like
if (!String.IsNullOrEmpty(inputName))
{
foreach (Aluno a in alunosMatriculados)
if (a.nomeAluno == inputName)
a.numFaltas = inputValue;
}
in above code can comapre id also instead of inputName in inner if condition
By this way can only alter your numFaltas and any other also that you want
I am getting a System.InvalidCastException at runtime with this code:
inf.Country = (Country)(int)rdr["Country"];
Model class:
public class BasicInfo
{
.....
public Gender Gender { get; set; }
public Country Country { get; set; }
}
public enum Gender
{
Male,
Female
}
public enum Country
{
Australia,
Bangladesh,
England,
France,
Usa
}
DbConnect class: the method return the entities list and it will pass through the controller's view.
usp_GetAllStudentData is a stored procedure that returns the list of records.
public List<BasicInfo> SelectStudent()
{
ConnectionString();//Contain Connection string
List<BasicInfo> entities = new List<BasicInfo>();
SqlCommand cmd = new SqlCommand("usp_GetAllStudentData", conn);
cmd.CommandType = CommandType.StoredProcedure;
conn.Open();
SqlDataReader rdr = cmd.ExecuteReader();
while(rdr.Read())
{
BasicInfo inf = new BasicInfo();
inf.FirstName = (string)rdr["FirstName"];
.....//other required value are assigned to class members.
//inf.Gender = (Gender)(int)rdr["Gender"];
inf.Country = (Country)(int)rdr["Country"]; // Getting run time exception here
entities.Add(inf);
}
return entities;
}
How the data is stored in the database
Can you guys let me know what is the best method to cast an enum value?
Or let me know if there is any alternative way to fix this issue.
Table Design
If your database field contains a NULL value then the result of your code is the Invalid Cast Exception
For example
object x = DbNull.Value; // A null value on the db is represented by DbNull.Value
inf.Country = (Country)(int)x; // Gives the Invalid Cast Exception
How to fix depends on what you want to do with null values. If you don't allow null values for countries then you should revise your code that accepts an invalid input and block these inputs (and not forget to set the Country field to NOT allow NULL values on the database table)
If you accept a null value then I suggest to add another entry to your country enum
public enum Country
{
Australia = 0,
Bangladesh,
England,
France,
Usa,
// <=== new countries should be added here....
Undefined = 9999
}
and change your reading code to
int ordinal = rdr.GetOrdinal("Country");
inf.Country = rdr.IsDBNull(ordinal) ? Country.Undefined
: (Country)(int)rdr["Country"];
From your comments it seems that you have stored the numeric value of the enum in a varchar column transforming your number in a string
If you want to convert back this string to the appropriate enum value then you should use Enum.TryParse, but the conversion back is not as simple as it seems.
So if you want to still check for null values then:
int ordinal = rdr.GetOrdinal("Country");
// Check for null value....
if(rdr.IsDBNull(ordinal))
inf.Country = Country.Undefined;
else
{
// OK, not null, but what if it is "ABC"??
if(!Enum.TryParse(rdr["Country"].ToString(), out inf.Country))
inf.Country = Country.Undefined;
// OK, but what if it is a number not defined in the coutry enum (IE "88")
if(!Enum.IsDefined(typeof(Country), inf.Country))
inf.Country = Country.Undefined;
}
As you can see, if there isn't a specific reason then I suggest to store the enum value as an integer and not as a string. This allow more flexibility in your code and in future changes to this variable.
try this
if (rdr["Country"]!=DBNull.Value)
{
inf.Country =(Country)Enum.ToObject(typeof(Country) , rdr["Country"].ToString());
}
EDIT: Why is Union() not excluding duplicates like it should?
I should have read the documentation before asking the original question. I didn't because everytime I used Union() was on lists of objects that didn't override Equals() and GetHashCode(), so even if the value of the fields of each of my objects in the lists were the same, they would be inside the new list Union() created. At first it would seem as if Union() didn't exclude duplicates and that was what I believed was true. But Union() does, in fact, exclude duplicates. And not only duplicates in both lists, but also duplicates within the same list. If my objects don't override Equals() and GetHashCode() they are not compared by value and that means that they are not seem as duplicates.
This was the confusion that made me ask this question.
Once I create a new List using Union() and then Select() the fields explicitly, "T" would become an anonymous type, which is compared by value. This way, objects with the same value of fields would be seem as duplicates. That is what is causing Union() to behave differently (or rather appear to behave differently). It always excludes duplicates but not always a type is compared by value, so objects with the same value of fields may or may not be seem as duplicates. It depends on the implementation of your custom class.
I guess that should have been the question: Why is Union() not excluding duplicates like it should? (as we've seen, it's because my objects were not really duplicates). Is that right?
----------------------
Original Question: LINQ Union + Select is removing duplicates automatically. Why?
I've always thought that Union() in Linq would return all values from the two lists even if they are the same. But my code is removing duplicates from the first list when I use 'Select()' right after a Union().
Imagine the classic probability problem of ball extraction, where I have different containers and I extract some number of different balls from the containers.
I have two lists of BallExtraction. Each list shows me the Id of the ball, the Id of the container that the ball was in, the number of balls I have extracted (Value) and its Color. But, for some reason, I have two different lists and I want to merge them.
Example Code:
class BallExtraction
{
public enum BallColor
{
Blue = 0,
Red = 1
}
public int Id { get; set; }
public int IdContainer { get; set; }
public int ValueExtracted { get; set; }
public BallColor Color { get; set; }
public BallExtraction() { }
public BallExtraction(int id, int idContainer, int valueExtracted, BallColor color)
{
this.Id = id;
this.IdContainer = idContainer;
this.ValueExtracted = valueExtracted;
this.Color = color;
}
}
And now I run the program that follows:
class Program
{
static void Main(string[] args)
{
List<BallExtraction> list1 = new List<BallExtraction>();
list1.Add(new BallExtraction(1, 1, 20, BallExtraction.BallColor.Blue));
list1.Add(new BallExtraction(1, 1, 20, BallExtraction.BallColor.Blue));
list1.Add(new BallExtraction(1, 1, 20, BallExtraction.BallColor.Red));
list1.Add(new BallExtraction(1, 2, 70, BallExtraction.BallColor.Blue));
list1.Add(new BallExtraction(2, 1, 10, BallExtraction.BallColor.Blue));
List<BallExtraction> list2 = new List<BallExtraction>();
list1.Add(new BallExtraction(3, 2, 80, BallExtraction.BallColor.Blue));
list1.Add(new BallExtraction(3, 2, 80, BallExtraction.BallColor.Red));
var mergedList = list1.Where(w => w.Color == BallExtraction.BallColor.Blue).Select(s => new
{
Id = s.Id,
IdContainer = s.IdContainer,
ValueExtracted = s.ValueExtracted
}).Union(list2.Where(w => w.Color == BallExtraction.BallColor.Blue).Select(s => new
{
Id = s.Id,
IdContainer = s.IdContainer,
ValueExtracted = s.ValueExtracted
}));
Console.WriteLine("Number of items: {0}", mergedList.Count());
foreach (var item in mergedList)
{
Console.WriteLine("Id: {0}. IdContainer: {1}. # of balls extracted: {2}", item.Id, item.IdContainer, item.ValueExtracted);
}
Console.ReadLine();
}
}
The expected output is:
Number of items: 5
Id: 1. IdContainer: 1. Value: 20.
Id: 1. IdContainer: 1. Value: 20.
Id: 1. IdContainer: 2. Value: 70.
Id: 2. IdContainer: 1. Value: 10.
Id: 3. IdContainer: 2. Value: 80.
But the actual output is:
Number of items: 4
Id: 1. IdContainer: 1. Value: 20.
Id: 1. IdContainer: 2. Value: 70.
Id: 2. IdContainer: 1. Value: 10.
Id: 3. IdContainer: 2. Value: 80.
Notice that the first list contains two extractions with the same values. The Id of the ball is 1, the Id of the container is 1, the number of balls extracted is 20 and they are both blue.
I found that when I switch the 'mergedList' to the code below, I get the expected output:
var mergedList = list1.Where(w => w.Color == BallExtraction.BallColor.Blue).Union(list2.Where(w => w.Color == BallExtraction.BallColor.Blue));
So, it seems that the 'Select' used right after the Union() is removing the duplicates from the first list.
The real problem is that I don't actually have a list of a simple type like in the example but I have a list of IEnumerable< T > (T is an anonymous type) and T has a lot of fields. I only want specific fields but I want all the new anonymous type duplicates. The only workaround I have found is if in the 'Select()' I add some field that is unique to each object T.
Is this working as intended? Should Union + Select remove duplicates?
Yes, it's the expected behaviour.
Union's doc states
Return Value Type: System.Collections.Generic.IEnumerable An IEnumerable that contains the elements from both input
sequences, excluding duplicates.
To keep duplicates, you have to use Concat(), not Union()
I have just changed my code so that now it stores some data in an enum instead of in a SQL Server table.
Here's the enum:
public enum ContentTypes : int
{
Article = 0,
Menu = 1,
ContentBlock = 3
}
I was running the following code:
var contentTypes =
(
from contentType in this._contentTypeService.GetContentTypes()
select new
{
id = contentType.ContentTypeId,
name = contentType.Name
}
);
How can I change this so that instead of taking the data from the content service it just queries the enum to data for contentTypes?
I think what you want is this
var contentTypes =
from value in Enum.GetValues(typeof(ContentTypes)).Cast<int>()
select new
{
id = value,
name = Enum.GetName(typeof(ContentTypes), value)
};
pswg might be right, but I am thinking you want something like this?
Here is code more direct to your question:
select new
{
id = (int)contentType,
name = contentType.ToString()
}
You can get the integer id simply by casting to an int and get the name of it by using its ToString (which may or may not be implicit here)
So, I am trying to programmatically add in a ModelFilter to my ObjectListView that will look at two (or more) columns and filters on each separately. Currently, I think that ObjectListView only supports one filter, but I may be missing something in the code/documentation.
As an example, one of my intended filters is to look at column "Active" and that has values of "A" or "T". Another column is a Supervisor Name. So, I want to find all entries where Supervisor name = "Smith" and Active = "A".
I can get the filter to work for either of these options separately using TextMatchFilter, but cannot figure out how to get both to work at the same time.
The minor problem I see is that if the Supervisor Name contains an "A", then using the standard Filter will return the whole row. I have been able to get around that by programmatically setting the Searchable property for columns to false if I don't want to look at them, and then turn them back on once the list is filtered. However, I have a feeling that if I turn Searchable on for the Supervisor column, I will get the unwanted results.
Does anyone know of a way to get the filter to work on multiple columns, using only the indicated columns for each filter?
(I have no sample code to show that helps in solving this. However, if you really want to see what I have for my filtering code, I will be happy to add that; it is in VB however).
Current Code - This looks at a value chosen by the user (searchMeth) and enables searching on that column. It then does the search for what was entered in the txtSearch box. However, in addition to this, I want to add in an additional filter for Supervisor. (See the AndAlso comment
olvEmps.UseFiltering = True
OlvColumn1.Searchable = False
OlvColumn2.Searchable = False
OlvColumn4.Searchable = False
OlvColumn3.Searchable = False
OlvColumn5.Searchable = False
Select Case searchMeth
Case "Name"
OlvColumn1.Searchable = True
Case "Employee Number"
OlvColumn2.Searchable = True
Case "Department"
OlvColumn3.Searchable = True
End Select
olvEmps.OwnerDraw = True
Dim tFilter As BrightIdeasSoftware.TextMatchFilter = BrightIdeasSoftware.TextMatchFilter.Contains(olvEmps, txtSearch.Text)
'andalso olvColumn5 = supeName?
olvEmps.ModelFilter = tFilter
olvEmps.DefaultRenderer = New BrightIdeasSoftware.HighlightTextRenderer(tFilter)
OlvColumn1.Searchable = True
OlvColumn2.Searchable = True
OlvColumn3.Searchable = True
OlvColumn4.Searchable = True
OlvColumn5.Searchable = True
I'm sure the PredicateBuilder solution will work, but ObjectListView comes with a simpler solution already.
TextMatchFilter can be limited to which columns it searches via the Columns property. Set this to an array of columns that you want to consider.
TextMatchFilter filter1 = TextMatchFilter.Contains(olvEmps, txtSearch.Text)
filter1.Columns = new [] { this.olvColumn1, this.olvColumn2 };
You can combine two filters using the CompositeAllFilter to match two or more other filters.
this.olvEmps.ModelFilter = new CompositeAllFilter(new List<IModelFilter> { filter1, filter2 });
Though I don't yet fully understand your deal, I'll give it a shot with the PredicateBuilder that is part of the LINQKit assembly which you can download here.
As such, filtering on multiple columns shall get easy. Perhaps shall you consider to reset the binding of your ObjectListView control once your source collection has been filtered.
Grossly, I would do about the following:
Load your datum;
Display them through data binding;
Once a column is clicked for filter, make a call to your "Filter" method which will apply your predicates;
Rebind your control with the new filtered collection.
Please refer to the PredicateBuilder documentation at the link provided previously. Another example to building dynamic filters is illustrated here: "How would this query translate into a dynamic Linq expression?" for a search engine I implemented.
In my case, the filters were applied directly against the database results. Aside, it can even be used in your situation with in-memory datum since it is Linq based.
I'm sure I'll be able to provide further assitance when you post your code sample for filtering the information.
EDIT #1
After I have read the code sample provided, here's what I believe would do the trick. As for the Searchable property, I am no familiar of this approach, so maybe I can miss something important out of your code and if it is so, feel free to point me what I could have missed. =)
Note that I assume that all of your datum are string, since I am verifying whether your datum is null or white space. Furthermore, the way I see it, to filter a result set is to bring visible only records which meet certain criterion. You don't want to see what doesn't meet the criterion. It's the same as a WHERE clause in SQL.
public class FilterCriterion {
public bool HasEmployeeName { get { return !string.IsNullOrWhiteSpace(EmployeeName); } }
public bool HasEmployeeNumber { get { return !string.IsNullOrWhiteSpace(EmployeeNumber); } }
public bool HasDepartment { get { return !string.IsNullOrWhiteSpace(Department); } }
public string EmployeeName { get; set; }
public string EmployeeNumber { get; set; }
public string Department { get; set; }
}
The FilterCriterion class shall be used to apply any filter that you want against your data source, collection or whatsoever.
var employees = LoadEmployeesFromUnderlyingDataStore();
var criterion = new FilterCriterion();
switch(searchMeth) {
case "Name": filter.EmployeeName = "the name to filter by"; break;
case "EmployeeNumber": filter.EmployeeNumber = "the number to filter by"; break;
case "Department": filter.Department = "the department to filter by"; break;
}
var filter = PredicateBuilder.True<Employee>(); // assuming you have an employee class.
if (criterion.HasEmployeeName)
filter.And(e => e.Name.ContainsLike(criterion.EmployeeName));
if (criterion.HasEmployeeNumber)
filter.And(e => e.EmployeeNumber.ContainsLike(criterion.EmployeeNumber));
if (criterion.HasDepartment)
filter.And(e => e.Department.ContainsLike(criterion.Department));
var filteredEmployees = employees.Where(filter);
// Supply your ObjectListView the way you're used to and this shall function.
Aside, you could also, if you have to deal with such string variables write a ContainsLike extension method to the string class.
namespace System {
public static class StringExtensions {
public static bool ContainsLike(this string input, string value) {
if (string.IsNullOrWhiteSpace(input) || string.IsNullOrWhiteSpace(value)) return false;
input = input.ToLower().RemoveDiacritics();
value = value.ToLower().RemoveDiacritics();
if (string.IsNullOrWhiteSpace(input) || string.IsNullOrWhiteSpace(value)) return false;
return input.Contains(value);
}
public static string RemoveDiacritics(this string input) {
return input == null ? null :
Encoding.ASCII.GetString(Encoding.GetEncoding(1251).GetBytes(input));
}
}
}
I do hope this helps, otherwise inform me of what I misunderstood from your question and we'll try to figure this out together.
Should you need the VB version of this code, I'll try to translate to the best of my VB knowledge.
This code is provided as is and has not been tested, except for both the string extension methods.