I built a wrapper around NpgSQL for a bunch of the methods I usually use in my projects' DAL. Two of them, I usually use to fill DTOs straight from a DataReader. Usually in a fill helper method, i'll instanciate the DTO and iterate through the properties mapping the Datareader's data to the corresponding property. The fill method is generated most of the time.
Since i allow many of the properties to be null or use the DTO's default values, I've used a method to check if the dataReader's data is valid for the property before filling in the prperty. So i'll have a IsValidString("fieldname") and a DRGetString("fieldname") methods, like so:
public bool IsValidString(string fieldName)
{
if (data.GetOrdinal(fieldName) != -1
&& !data.IsDBNull(data.GetOrdinal(fieldName)))
return true;
else
return false;
}
public string DRGetString(string fieldName)
{
return data.GetString(data.GetOrdinal(fieldName));
}
My fill method is delagated to whatever method executed the query and looks like:
public static object FillObject(DataParse<PostgreSQLDBDataParse> dataParser)
{
TipoFase obj = new TipoFase();
if (dataParser.IsValidInt32("T_TipoFase"))
obj.T_TipoFase = dataParser.DRGetInt32("T_TipoFase");
if (dataParser.IsValidString("NM_TipoFase"))
obj.NM_TipoFase = dataParser.DRGetString("NM_TipoFase");
//...rest of the properties .. this is usually autogenerated by a T4 template
return obj;
}
This was working fine and dandy in NpgSQL pre 2.02. . When the GetOrdinal method was called, and if the field was inexistent in the dataReader, I'd simply get a -1 returned. Easy to return false in IsValidString() and simply skip to the next property. The performace hit from checking inexistent fields was practically neglectable.
Unfortunately, changes to NpgSQL make GetOrdinal throw an exception when the field doesn't exist. I have a simple workaround in which I wrap the code in a try /catch and throw false within the catch. But I can feel the hit in performance, especially when I go in to debug mode. Filling in a long list takes minutes.
Suposedly, NpgSQL has a parameter that can be added to the connection string (Compatability) to support backward compatabilty for this method, but I've never got that to work correctly (I always get an exception because of a mal formed connection string). Anyway, I'm looking for suggestions for better workarounds. Any better way to fill in the object from the datareader or even somehow work around the exception problem?
I have created a solution to my problem, that doesn't require great changes, and presents interesting performance (or so it seems). Might just be a new parsing library / wrapper.
Basicly, I'll iterate through the dataReader's fields, and copy each to a Collection (in my case a List). Then I'll check for valid data and if considered valid, I'll copy the data to the object's property.
So I'll have:
public class ParserFields
{
public string FieldName { get; set; }
public Type FieldType { get; set; }
public object Data { get; set; }
}
and I'll fill the object using:
public static object FillObjectHashed(DataParse<PostgreSQLDBDataParse> dataParser)
{
//The the Field list with field type and data
List<ParserFields> pflist = dataParser.GetReaderFieldList();
//create resulting object instance
CandidatoExtendido obj = new CandidatoExtendido();
//check for existing field and valid data and create object
ParserFields pfdt = pflist.Find(objt => objt.FieldName == "NS_Candidato");
if (pfdt != null && pfdt.FieldType == typeof(int) && pfdt.Data.ToString() != String.Empty)
obj.NS_Candidato = (int)pfdt.Data;
pfdt = pflist.Find(objt => objt.FieldName == "NM_Candidato");
if (pfdt != null && pfdt.FieldType == typeof(string) && pfdt.Data.ToString() != String.Empty)
obj.NM_Candidato = (string)pfdt.Data;
pfdt = pflist.Find(objt => objt.FieldName == "Z_Nasc");
if (pfdt != null && pfdt.FieldType == typeof(DateTime) && pfdt.Data.ToString() != String.Empty)
obj.Z_Nasc = (DateTime)pfdt.Data;
//...
return obj;
}
I timed my variations, to see the diferences. Did a search that returned 612 results. First I queried the database twice too take in to account the first run of the query and the subsequent diferences related to caching ( and that where quite significant). My FillObject method simply created a new instance of the desired object to be added to the results list.
1st query to List of object's instances : 2896K ticks
2nd query (same as first) : 1141K ticks
Then I tried using the previous fill objects
To List of desired object, filled with return data or defaults, checking all of the objects properties: 3323K ticks
To List of desired objects, checking only the object's properties returned in the search: 1127K ticks
To list of desired objects, using lookup list, checking only the returned fields: 1097K ticks
To list of desired objects, using lookup list, checking all of the fields (minus a few nested properties): 1107K ticks
The original code i was using was consuming nearly 3 times more ticks than when using a method limited to the desired fields. The excpetions where killing it.
With the new code for the fillobject method, the overhead for checking inexistente fileds mas minimal compared to just checking for the desired fields.
This seems to work nice, for now at least. Might try looking for a couple of optimizations.
Any sugestion will be appreciated!
Related
So currently, you can imagine I have 1 method that is the constructor that funcitons like
info.PersonalInfo=getPersonalInfo(Id);
info.MedicalInfo=getMedicalInfo(Id);
Thing is, all of those get data and get binarys are repeating 95% of the code
using (CVDataEntities data = new CVDataEntities())
{
var temp = data.PersonalInfo.Where(m => m.Id == Id).FirstOrDefault();
return temp;
}
The only thing that changes is instead of PersonalInfo its MedicalInfo.
I thought of using a switch and just sending a number as the selector for which specific object I would want.
But the problem is the method is made so that it can only return
public IEnumerable<PersonalInfo> getPersonalInfo (string Id)
Is there any way for me to make a IEnumerable that lets me return any object, or is there a better way to go about this. I want to do it mostly to reduce the code from 400 lines down to 200 at most.
Try using generic methods, you will be able to specify the return type of your function when you call it. This could make your code look like this :
public IEnumerable<T> getInfo<T>(string id)
{
// Some code
}
// Calling the function
info.PersonalInfo = getInfo<PersonalInfo>(Id);
info.MedicalInfo = getInfo<MedicalInfo>(Id);
But be careful while using it, cause the compiler won't know what type T is (it is only defined at runtime) so it could lead to some errors while processing the data (like missing properties / methods exclusive to a specific type)
EDIT : Johnathan Barclay made a good point by commenting that the // some code bit is relevant and asked "How would the correct property be selected on data? How do you access an Id property on T?"
To get the correct property and access an Id property, you could use System.Reflection and add a string parameter to get the name of the property you want to use, and another to give the Id property name to the function:
public IEnumerable<T> getInfo<T>(string id, string propertyToReadName, string propertyToCompareName)
{
using (CVDataEntities data = new CVDataEntities())
{
// Getting the enumerable not filtered first
IEnumerable<T> unfilteredList = (IEnumerable<T>)data.GetType() // Get the type
.GetProperty(propertyToReadName, typeof(T)) // Get the property (PersonalInfo or MedicalInfo)
.GetValue(data); // Get the value of this property in the `data` instance
// Filtering the list
IEnumerable<T> filteredList = unfilteredList.Where(m =>
typeof(T).GetProperty(propertyToCompareName) // Get the "id" property using parameter
.GetValue(m) // Get the "id" value of m instance
.Equals(id)); // Check if it equals the id given as parameter
return filteredList;
}
}
// Calling the function
info.PersonalInfo = getInfo<PersonalInfo>(Id, "PersonalInfo", "Id");
info.MedicalInfo = getInfo<MedicalInfo>(Id, "MedicalInfo", "Id");
If you want to return a single element instead of an IEnumerable don't forget to change the return type of the function from IEnumerable<T> to T and add .FirstOrDefault() at the return line
Note that you could also give another value to the parameter propertyToCompareName and make a comparison to another property of the T class
I have a list of integers (Levels). I want to initialize a nested Object of Filter called myFilter as below(Filter is a class with two properties: Value and NextFilter):
var myFilter = new Fliter{
Value = Levels[0],
NextFilter = new Filter{
Value = Levels[1],
NextFilter = new Filter{
Value = Levels[2],
NextFilter = new Filter{
Value = Levels[n],
NextFilter = null
}
}
}
}
Level's count is not static and depends on the input list (I have a multi select list that generates Level)
How can I do that?
This is a classic event for using - the technique of a method that calls itself:
public static Filter CreateFilter(List<int> values) => values.Any() ? new Filter //If the list contains elements, create the filter
{
Value = values.First(), //assign the first item of the values to the value property
NextFilter = CreateFilter(values.Skip(1).ToList()) //Create the rest of the nested object with the rest of the values
} : null; //If there aren't any items left in the list, return null and stop the recursion
You could of course do it in the constructor as well:
public Filter(List<int> values)
{
if (!values.Any()) return;
Value = values.First();
NextFilter = values.Count > 1 ? new Filter(values.Skip(1).ToList()) : null;
}
For more information about recursion, take a look at this: https://www.dotnetperls.com/recursion, for more information on nested classes read through this: https://www.dotnetperls.com/nested-class.
A few more information on recursion:
You can actually achieve everything through recursion - you don't even need loops. That's the reason why in languages like Haskell loops don't exist.
The simplest recursive function is:
public static void EndlessLoop()
{
//Loop body
EndlessLoop();
}
However, even Resharper suggests to convert it to a loop:
Another example, if you want to get the sum of a list you could do:
public static int Sum(List<int> summands) => summands.Count > 0
? summands.First() + Sum(summands.Skip(1).ToList())
: 0;
But those examples aren't useful in C#, as C# isn't a functional programming language, which causes recursion to be slower than loops. Furthermore recursion often causes a StackOverflowException (fitting to this site). If you run the endless loop recursion, it doesn't even take a second till your stack is full.
The reason for this is, that C# adds the address, from which a method got called, to the stack. If a method is called very often (and in 1 second a lot of recursive calls are made) a lot of addresses are added to the stack, so that it overflows.
However I still think, even though those examples aren't useful in c#, that it's quite useful to be able to handle recursion. Recursion is for example the only way to explore a directory structure, for getting for example all files:
public static List<FileInfo> GetAllFiles(DirectoryInfo directory) => directory.GetFiles()
.Concat(directory.GetDirectories().SelectMany(GetAllFiles))
.ToList();
And, as you experienced, it's the only way to fill a nested class from a list properly.
Just make a constructor of Filter, that will get Levels array as a parameter, that will set it's Value as level[0], and init NextFilter = new Filter(level.Skip(1)). Something like that. And it will recursively initialize your object.
I am trying to figure out why the following code throws a StackOverflowException (I am finally posting a StackoverflowException in SO!).
Debugging seems to point out that the p.GetValue(this) is generating further calls.
What is actually triggering the infinite call chain ? Is it because p.GetValue(this) ultimately returns an instance of the current object, and thus acts as if constructing a new instance (and every object that constructs itself within its construction will lead to Stackoverflow exceptions) ?
My intent with the following code is to have an object being capable of telling how many of its properties have null/space/empty values.
public class A
{
public string S1 { get; set; }
public string S2 { get; set; }
public int NonInitializedFields
{
get
{
int nonNullFields = 0;
var properties = this.GetType().GetProperties();
foreach (var p in properties)
{
var value = p.GetValue(this);
if (value == null || string.IsNullOrWhiteSpace(value.ToString()))
nonNullFields++;
}
return nonNullFields;
}
}
}
//the following throws a StackOverflowException (the construction line itself)
A a1 = new A1{ S1 = "aaa"};
Console.WriteLine(a1.NonInitializedFields);
P.S. My idea originally involves only simple string properties, nothing else, so whatever problems may arise with this approach with other types are not relevant.
You have a property, which, when you execute the "get" accessor, finds all the properties and fetches their value. So it executes itself, recursively.
If you only want string properties, you should check the property type before fetching the value:
var properties = GetType().GetProperties().Where(p => p.PropertyType == typeof(string));
At that point, as your NonInitializedFields property doesn't have a return type of string, it won't be executed.
Personally I would make this a method call rather than a property anyway, mind you. That would also fix the issue, as the method wouldn't find itself when looking for properties.
I would also rename it, as:
A property isn't necessarily backed by a field
A field could be explicitly initialized as null or a reference to a string containing only whitespace
A method called GetNonWhitespaceStringPropertyCount() would be more accurate, IMO. You can also make the whole implementation a LINQ query:
return GetType().GetProperties()
.Where(p => p.PropertyType == typeof(string))
.Select(p => p.GetValue(this))
.Count(v => !string.IsNullOrWhitespace((string) v));
Note that I've fixed the next issue in your code - you're meant to be counting non-null/empty values, but you're actually counting null/empty ones.
,Hi
List<Claimant> list = (from c in CacheManager.ClaimantList.List
where
c.Fullname.Replace("i", "İ").Replace("ı","I").ToUpper().Contains(searchKey.Replace("i", "İ").Replace("ı", "I").ToUpper())
|| c.IdentityNumber.Replace("i", "İ").Replace("ı", "I").ToUpper().Contains(searchKey.Replace("i", "İ").Replace("ı", "I").ToUpper())
|| c.TaxNumber.Replace("i", "İ").Replace("ı", "I").ToUpper().Contains(searchKey.Replace("i", "İ").Replace("ı", "I").ToUpper())
select c).Take(20).ToList<Claimant>();
If Taxnumber is null or "" i get exception because of null data.
My question:
How can i set Taxnumber == 0 , if Taxnumber is null or "" ?
Any help will be appreciated.
Thanks.
You can do:
from c in CacheManager.ClaimantList.List
let taxNumber = c.TaxNumber == null || c.TaxNumber == "" ? "0" : c.TaxNumber
where ...
and then use the taxNumber variable rather than the column.
If you just want certain columns and you don't need the whole Claimant object, you can put something into a select
from c in ClaimantList
where (...)
select new {c.FullName, c.IdentityNumber, TaxNumber = String.IsNullOrEmpty(c.TaxNumber) ? "0" : c.TaxNumber}
You now have an anonymous type with three fields: original FullName, original IdentityNumber and modified TaxNumber.
You could also create a new Claimant for each value by calling its constructor each time:
from c in ClaimantList
where (...)
select new Claimant() {FullName = c.FullName, IdentityNumber = c.IdentityNumber, TaxNumber = String.IsNullOrEmpty(c.TaxNumber) ? "0" : c.TaxNumber}
(I don't know what the constructor of Claimant is like, you might do this slightly differently and set those values in the constructor rather than in the initializer. Or you could write a new constructor.) If the constructor does something non-trivial, it might be wasteful of resources to call it this many times.
In either case, it is stylistically nice to put the conversion (String.IsNullOrEmpty(TaxNumber) ? "0" : TaxNumber or whatever) into its own function somewhere, so that you can change what conversion you do later (see below), and don't have to repeat the code in multiple places.
Another option is that you could use the objects you have, but change the TaxNumber as required. LINQ isn't really the best way of doing this, as you are basically applying side-effects. (LINQ likes to supply a new container with the right data in it, rather than change the data in the original container.) You should really run foreach outside of the Linq code, like this:
List<Claimant> list = from ...
where ...
select ...
foreach (Claimant claimant in list)
{
if (String.IsNullOrEmpty(claimant.TaxNumber))
{ claimant.TaxNumber = "0"; }
}
Ideally you do this after the Take(20) so that you only do it the number of times you need.
Again, putting the conversion in a function will be neater and nicer:
List<Claimant> list = from ...
where ...
select ...
foreach (Claimant claimant in list)
{
claimant.TaxNumber = NormalizeTaxNumber(claimant.TaxNumber); }
}
// ...
public static string NormalizeTaxNumber(string n)
{
return String.IsNullOrEmpty(n) ? "0" : n;
}
However, if you have gone down this route, the next option is to add a method to Claimant which does this change:
List<Claimant> list = from ...
where ...
select ...
foreach (Claimant claimant in list)
{
claimant.NormalizeTaxNumber();
}
public class Claimant
{
// ...
public void NormalizeTaxNumber()
{
if (String.IsNullOrEmpty(TaxNumber))
{ TaxNumber = "0"; }
}
}
and to call this from the foreach loop.
Or, use a different property than TaxNumber:
public class Claimant
{
// ...
public string NormalTaxNumber
{
get { return String.IsNullOrEmpty(TaxNumber) ? "0" : TaxNumber; }
}
}
The advantage of the first strategy is that you only have to call it once - the advantages of the second are that it keeps the original value still available (in the TaxNumber property), and that if you have a bunch of Claimant objects, you don't have to remember whether you have normalized them or not.
You could also use a combination of the two methods: add a new property NormalTaxNumber which converts TaxNumber when needed, and which caches the result so that conversion doesn't have to be done again.
public class Claimant
{
// ...
private string m_normalTaxNumber;
private string ConvertedTaxNumber
{
get { return String.IsNullOrEmpty(TaxNumber) ? "0" : TaxNumber; }
}
public string NormalTaxNumber
{
get
{
if (m_normalTaxNumber == null)
{ m_normalTaxNumber = ConvertedTaxNumber; }
return m_normalTaxNumber;
}
}
}
This only does the calculation once, keeps the original still available, and doesn't require to remember if you've called it before or not. If TaxNumber (the original value) isn't readonly, this is probably more trouble than it's worth as you will have to invalidate the cached value.
If you are never, never going to need to know whether the TaxNumber was originally null, empty or "0", the best advice (and the last strategy) is to convert to the form you want as soon as possible, preferably in the Claimant constructor, if the value of TaxNumber is known there.
If you are getting Claimant objects from a database, you could take this to its logical limit by doing the conversion on the database, either in a stored proc or in a view. If you are using LinqToSql to get the list of Claimant objects, a view could work for you but a stored proc might not.
I have assumed throughout that you want TaxNumber to be available as a string, and that by 0 you mean the string "0". If this isn't the case, and you actually want convert to an int (or similar), some of the strategies above will still work. You can select the converted value as an int in an anonymous type, you can make a new property NormalTaxNumber (with int type), whether cached or not cached, or you can do the conversion upon creation of a Claimant object. Obviously you can't overwrite the string TaxNumber with an int.
If you are parsing the string to an int, things like NormalTaxNumber with caching become more worthwhile, because the conversion from string to int is more costly. (Checking for null or "" is actually very fast, however I thought it valuable to go through some different options anyway.)
Note that almost all of these should still be available to you if you can't modify the Claimant class. You can't write a new constructor, but you can write a factory method which encapsulates exactly the same behavior as a constructor. You can add NormalizeTaxNumber as an extension method, and while you can't add properties, you can add extension methods with no arguments which work almost exactly like properties.
My last observation is that "0" might not necessarily be a better value for missing data than null or "". Either of the latter is more commonly used to indicate missing values, especially null. Perhaps you should choose one of those as the default (and maybe apply one of the above strategies in reverse to enforce it as the only 'N/A' value?) If it's just a question of it looking nice when you print the object out, you could override ToString() to swap in the "0" only when needed.
I have a class with lots of properties. A shallow copy is enough to fully replicate the object.
I need to compare an object just to check if it contains exactly the same values as another.
My ideas:
The first and most obvious solution is just to create a huge method block that compares each property, one after the other.
The second would be to serialize each object and hash the file or do some sort of md5 checksum on it. (Would this actually work?)
The third is to do some sort of reflection on the object, which would automate the first option, but create an added level of complexity.
Speed isn't really an issue.
I'm interested to hear thoughts, or any other methods I am missing to do such a thing.
Edit:
Thanks all. My solution (Modified to now be recursive on generic items):
public static bool IsSame<T>(T objA, T objB)
{
var type = typeof(T);
var properties = type.GetProperties();
foreach (var pi in properties.Where(a => a.CanRead))
{
if (pi.Name == "Item")
{
var piCount = properties.FirstOrDefault(a => a.Name == "Count");
int count = -1;
if (piCount != null && piCount.PropertyType == typeof(System.Int32))
count = (int)piCount.GetValue(objA, null);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
dynamic child1 = pi.GetValue(objA, new object[] { i });
dynamic child2 = pi.GetValue(objB, new object[] { i });
return IsSame(child1, child2);
}
}
}
else
{
var val1 = type.GetProperty(pi.Name).GetValue(objA, null);
var val2 = type.GetProperty(pi.Name).GetValue(objB, null);
if (val1 != val2 && (val1 == null || !val1.Equals(val2)))
return false;
}
}
return true;
}
Most serializers are designed to ensure that data retains its integrity during serialization and deserialization, not to produce a consistent serialized format. I would avoid using serialization for this purpose.
You may consider implementing IEquatable, to have each instance capable of comparing itself with instances of the same type. Or a class do do the comparisons for you that implements IEqualityComparer. How they do this comparison may be the 'big method' that compares properties one after the other, or uses reflection.
Reflection can be a fairly quick and simple way to achieve your goal but can cause problems down the line (for example if someone adds a property to your type that should not be included for comparing equality), but obviously the converse is also true (someone adds a property that should be checked for equality, but the equality comparison isn't updated). Which approach you use should generally be decided by how comfortable the team is with each approach in tandem with the context in which the class will be used.
In your case I'd probably recommend using the reflection based approach since you wish to check the result of a shallow clone operation, so all properties should be equal.
As an aside, I'd recommend using the MemberwiseClone method to create the clone, which would lessen the need for such stringent tests.
The third option (reflection) would be the slowest, but it would also be the most robust/testable.
The hash code would be very similar to the first option, since you would have to call all of your member variables, so 1 and 2 would require you to update your .Equals(obj) and .GenerateHash() methods every time you modify your member variable lists.
Here is some code to get you started:
foreach (FieldInfo field in this.GetType().GetFields())
{
if (o[field.Name] == null)
{
if (!field.GetValue(this).Equals(o[field.Name]))
return false;
}
else
{
return false;
}
}
return true;
Another thought is that if the properties return simple value types you could group them into immutable value types of their own. For instance, if you have a customer with properties string Address1 string Address2 string City string State string Zip, you could create a value type Address that implements its own equality comparer and use that.
Not sure if this applies to your situation, but I've found that when I have a class with a lot of properties, it is often possible to do this, and it tends to make my classes simpler and easier to reason about.
If you serialize you have to specify the serialization order on each Field/Property to ensure that all data is serialized int the same order. But all you would achieve is to implement GetHashCode() in an external class.
GetHashCode() has some examples on how to override it, so look there first.
If your class has a lot of fields, and you don't want to write all the code by hand. You could use reflection to autogenerate the code. If your class changes from time to time then you could create a partial class with the GetHashCode() implementation in a T4 template.