Easier way to reduce this code - c#

I have the following code
SetField("TextField1", ( item.FirstName == null || item.FirstName[0] == null)
? "" : item.FirstName[0].Value);
SetField("TextField2", ( item.MiddleName == null || item.MiddleName[0] == null)
? "" : item.MiddleName[0].Value);
SetField("TextField3", ( item.LastName == null || item.LastName[0] == null)
? "" : item.LastName[0].Value);
................
like this 50-60 lines
Is there a way I can write a function and pass in parameters to reduce this code
(say for example )
void Helper(string fieldName, somethinghere )
{
SetField(fieldName,usesomethinghere);
}

We don't know the data type of the properties of item, but assuming it's T, if you define (overload):
void SetField(string fieldName, T[] itemProperty)
{
SetField(fieldName,
itemProperty == null || itemProperty[0] == null ? "" : itemProperty[0].Value);
}
then your 50-60 lines can be reduced to:
SetField("TextField1", item.FirstName);
SetField("TextField2", item.MiddleName);
SetField("TextField3", item.LastName);
...
Is that what you're looking for?

What about creating a new read-only property in the Item class?
Something like:
public String FirstName_for_display {
get {
if(FirstName == null || FirstName[0] == null)
return "";
return FirstName[0].Value;
}
}
And called your SetField with something like:
SetField("TextField1", item.FirstName_for_display)

try something like:
Private void fieldsSetter(string[] fieldnames, object[] items)
{
for(int s=0; s<fieldnames.Count(); s++)
{
SetField(fieldnames[s], (((item)items).FirstName == null || ((item)items).FirstName[0] == null) ? "" : ((item)items).FirstName[0].Value);
}
}
not tested though....

Related

i updated my project from dotnet 2.1 to 6 and some base repository function return 500

error in debugger
im trying to do sothing like this but need help with how
upgrate my project from dotnet 2.1 to 6
my base function now return 500
using vscode
i need to check if IsActive property is exist in that model from base repo that im using generic model
public virtual async Task<IEnumerable<TPickerDto>> GetForPickerAsync([Optional] List<string> fieldsForInclude, [Optional] Dictionary<string, ItemsPermissions> permissions)
{
IQueryable<TModel> listFromDb = this._context.Set<TModel>()
.Where(r => (r.GetType().GetProperty("IsActive") != null &&
r.GetType().GetProperty("IsActive").GetValue(r) != null &&
(bool)r.GetType().GetProperty("IsActive").GetValue(r) == true) ||
(r.GetType().GetProperty("IsActive") == null) ||
(r.GetType().GetProperty("IsActive").GetValue(r) == null));
if (permissions != null)
{
if (permissions.ContainsKey("allowedUnits") && permissions.ContainsKey("allowedSites"))
{
if (permissions.GetValueOrDefault("allowedUnits").All && !permissions.GetValueOrDefault("allowedSites").All)
{
listFromDb = listFromDb.Where(r => r.GetType().GetProperty("SiteId").GetValue(r) == null
|| permissions.GetValueOrDefault("allowedSites").Indexes.Contains((int)r.GetType().GetProperty("SiteId").GetValue(r)));
}
else
{
if (!permissions.GetValueOrDefault("allowedUnits").All && permissions.GetValueOrDefault("allowedSites").All)
{
listFromDb = listFromDb.Where(r => r.GetType().GetProperty("UnitId").GetValue(r) == null
|| permissions.GetValueOrDefault("allowedUnits").Indexes.Contains((int)r.GetType().GetProperty("UnitId").GetValue(r)));
}
else
{
if (!permissions.GetValueOrDefault("allowedUnits").All && !permissions.GetValueOrDefault("allowedSites").All)
{
listFromDb = listFromDb.Where(r => (r.GetType().GetProperty("UnitId").GetValue(r) == null
|| permissions.GetValueOrDefault("allowedUnits").Indexes.Contains((int)r.GetType().GetProperty("UnitId").GetValue(r)))
&& (r.GetType().GetProperty("SiteId").GetValue(r) == null
|| permissions.GetValueOrDefault("allowedSites").Indexes.Contains((int)r.GetType().GetProperty("SiteId").GetValue(r))));
}
}
}
}
else
{
if (permissions.ContainsKey("allowedUnits"))
{
listFromDb = listFromDb
.Where(r => permissions.GetValueOrDefault("allowedUnits").All
|| r.GetType().GetProperty("UnitId").GetValue(r) == null
|| permissions.GetValueOrDefault("allowedUnits").Indexes.Contains((int)r.GetType().GetProperty("UnitId").GetValue(r)));
}
if (permissions.ContainsKey("allowedSites"))
{
listFromDb = listFromDb
.Where(r => permissions.GetValueOrDefault("allowedSites").All
|| r.GetType().GetProperty("SiteId").GetValue(r) == null
|| permissions.GetValueOrDefault("allowedSites").Indexes.Contains((int)r.GetType().GetProperty("SiteId").GetValue(r)));
}
}
}
// Import all the navigation properties
if (fieldsForInclude != null)
{
listFromDb = _JoinNavigationProperties(listFromDb, fieldsForInclude);
}
IEnumerable<TPickerDto> mappingList = _mapper.Map<IEnumerable<TPickerDto>>(listFromDb);
return mappingList;
}
Starting from dotnet core 3, Ef will throw an exception if a Linq query couldn't be translated to SQL and results in Client-side evaluation. In earlier versions you would just receive a warning. You will need to improve your Linq query so that it can be evaluated on client side.
Refer to this link for details,
https://learn.microsoft.com/en-us/ef/core/querying/client-eval
You are using reflection to do the query, why not use the property directly? If your boolean can be be NULL then declare the type as bool? IsActive. That way you can check for null in the where,
this._context.Set<TModel>().Where(r => (r.IsActive==true))
In case you are trying to create a repository then try declaring an interface that has IsActive as a field.
interface ISoftDeleteTarget
{
public IsActive{get;}
}

Concatenate two strings and get null if both are null

I am looking for a solution to concatenate two string values and get null as a result if both are null.
None of string1 + string2, string.Concat(string1, string2), string.Join(string1, string2) work. Research shows that is due to the fact, that these methods internally treat null as empty string.
How to solve this?
Since your actual formula is
(a + b) ?? (c + d) // assumes that null + null == null in (a + b)
I suggest rewriting it into
a == null && b == null ? c + d : a + b
which provides the expected result:
if both a and b are null we have c + d
a + b otherwise
If you want to have null (not empty string) when all a, b, c, d are null:
a == null && b == null ?
c == null && d == null
? null
: c + d
: a + b;
Something like this?
public class StringTest
{
public string CustomConcat(string one, string two) =>
one == null && two == null
? null
: string.Concat(one, two);
[Test]
public void ConcatTest()
{
Assert.IsNull(CustomConcat(null, null));
Assert.AreEqual("one", CustomConcat("one", null));
Assert.AreEqual("two", CustomConcat(null, "two"));
Assert.AreEqual("onetwo", CustomConcat("one", "two"));
// finally, a test for (a + b) ?? (c + d)
Assert.AreEqual("threefour", CustomConcat(null, null) ?? CustomConcat("three", "four"));
}
}
Yes, different method calls treat different preconditions, but you can always create your own function to handle "custom" preconditions.
As the most simple option you can try something like this:
String concatenateStrings(string s1, string s1) {
return (s1 == null && s2 == null)? null : String.concat(s1,s2);
}
You could do this:
var textResult = string.Empty;
if (string.IsNullOrWhiteSpace(text1) &&
string.IsNullOrWhiteSpace(text2))
{
textResult = null;
}
else
if (!string.IsNullOrWhiteSpace(text1) &&
string.IsNullOrWhiteSpace(text2))
{
textResult = text1;
}
else
if (string.IsNullOrWhiteSpace(text1) &&
!string.IsNullOrWhiteSpace(text2))
{
textResult = text2;
}
textResult = $"{text1} {text2}";
or in a better way:
textResult = (!string.IsNullOrWhiteSpace(text1) &&
string.IsNullOrWhiteSpace(text2)) ?
text1 :
(string.IsNullOrWhiteSpace(text1) &&
!string.IsNullOrWhiteSpace(text2)) ?
text2 :
(string.IsNullOrWhiteSpace(text1) &&
!string.IsNullOrWhiteSpace(text2)) ?
text2 :
$"{text1} {text2}";

Updating different Objects that have same properties

In my Code, i've got three (or more...) different objects, that all have the same properties (e.g. TrackingItemType, ReaderID etc).
They are derived from CounterBase (which does not have the Properties needed, but others).
Now i want to iterate through a Collection of those objects. In the Collection, all of the three objects can occur. Therefore, currently i've implemented the "update" for each object seperately.
Question: How can I avoid that duplicate Code written? Is there any
pattern available to update the different objects with same
properties?!
THANKS!
Method of interest:
private void UpdateTrackingCounters(Reading readingData, TrackingItemType trackingItemType, string trackingCounterType)
{
try
{
foreach (CounterBase counter in this.TrackingCounters)
{
if (typeof(TrackingSimpleCounter).IsInstanceOfType(counter))
{
TrackingSimpleCounter trackingCounter = (TrackingSimpleCounter)counter;
if (trackingCounter.TrackingCounterType == trackingCounterType)
{
if ((trackingCounter.ReaderID == 0
&& trackingCounter.TrackingItemType == null)
|| (trackingCounter.ReaderID == 0
&& trackingCounter.TrackingItemType == trackingCounter.TrackingItemType)
|| (trackingCounter.ReaderID == readingData.ReaderId
&& trackingCounter.TrackingItemType == null)
|| (trackingCounter.ReaderID == readingData.ReaderId
&& trackingCounter.TrackingItemType == trackingCounter.TrackingItemType)
)
{
trackingCounter.IncreaseOne();
}
}
}
else if (typeof(TrackingIntervalBasedRollingCounter).IsInstanceOfType(counter))
{
TrackingIntervalBasedRollingCounter trackingCounter = (TrackingIntervalBasedRollingCounter)counter;
if (trackingCounter.TrackingCounterType == trackingCounterType)
{
if ((trackingCounter.ReaderID == 0
&& trackingCounter.TrackingItemType == null)
|| (trackingCounter.ReaderID == 0
&& trackingCounter.TrackingItemType == trackingCounter.TrackingItemType)
|| (trackingCounter.ReaderID == readingData.ReaderId
&& trackingCounter.TrackingItemType == null)
|| (trackingCounter.ReaderID == readingData.ReaderId
&& trackingCounter.TrackingItemType == trackingCounter.TrackingItemType)
)
{
trackingCounter.IncreaseOne();
}
}
}
else if (typeof(TrackingTriggerBasedRollingCounter).IsInstanceOfType(counter))
{
TrackingTriggerBasedRollingCounter trackingCounter = (TrackingTriggerBasedRollingCounter)counter;
if (trackingCounter.TrackingCounterType == trackingCounterType)
{
if ((trackingCounter.ReaderID == 0
&& trackingCounter.TrackingItemType == null)
|| (trackingCounter.ReaderID == 0
&& trackingCounter.TrackingItemType == trackingCounter.TrackingItemType)
|| (trackingCounter.ReaderID == readingData.ReaderId
&& trackingCounter.TrackingItemType == null)
|| (trackingCounter.ReaderID == readingData.ReaderId
&& trackingCounter.TrackingItemType == trackingCounter.TrackingItemType)
)
{
trackingCounter.IncreaseOne();
}
}
}
}
}
catch (Exception ex)
{
this.Trace.Error(ex);
}
}
Define an interface that contains the properties and method you need:
interface ITrackable
{
int ReaderID;
string TrackingItemType;
void IncreaseOne();
}
And add it to the declaration of each class that has them:
class TrackingSimpleCounter : CounterBase, ITrackable
class TrackingIntervalBasedRollingCounter: CounterBase, ITrackable
class TrackingTriggerBasedRollingCounter : CounterBase, ITrackable
If all the classes truly share those properties, you won't have to implement any of the interface, since it'll already be present.
Then all you need is
foreach (ITrackable counter in this.TrackingCounters)
{
if ((counter.ReaderID == 0 && counter.TrackingItemType == null)
|| (counter.ReaderID == 0 && counter.TrackingItemType == counter.TrackingItemType)
|| (counter.ReaderID == readingData.ReaderId && counter.TrackingItemType == null)
|| (counter.ReaderID == readingData.ReaderId && counter.TrackingItemType == counter.TrackingItemType)
)
{
counter.IncreaseOne();
}
}
Although unless I misunderstand your logic all you truly need is:
foreach (ITrackable counter in this.TrackingCounters)
{
if (counter.ReaderID == 0 || counter.ReaderID == readingData.ReaderID)
{
counter.IncreaseOne();
}
}
Or if you want to use LINQ:
foreach (var counter in this.TrackingCounters.OfType<ITrackable>().Where(c => c.ReaderID == 0 || c.ReaderID = readingData.ReaderID))
{
counter.IncreaseOne();
}
Factorize
You can extract the common properties into one new common Object, and make both of your class have a reference property to that object.
This way, when you update this object, both of your original objects will have the most up-to-date values, without risk to forgot to update one of the properties.

ASP.NET MVC5 Entity Framework 6 get bool = true and bool = false LINQ

I have a table that I am filtering on.
There is a filter for values 'include' which can be true or false.
I have a filter that has 3 options: true, false, & all.
So, when the filter is true, it should return rows where include = 'true'; when the filter is 'false', return where include = false; and when 'all' return where include = true or false.
Here is my code, that is not working, but I think it should be.
private ICollection<AggregationEntityViewModel> getEntities(AggregationPracticeDetailsViewModel apdvm)
{
bool? filterInclude = Convert.ToBoolean(apdvm.Filter_IncludeValue);
var a = (from e in _repository.GetAll<Entity>()
where e.include == filterInclude != null ? (bool)filterInclude : (true || false)
select e
return a;
}
It is currently returning 0 rows when filter is set to 'All' or 'False', and returning all rows when set to 'Yes'.
FYI, I have ommitted lots of code for clarity's sake.
Please help...thanks!
*EDIT: I've displayed all the code, so you can see why I want to keep it all in linq query. Thanks for all the offered solutions. I see that most solutions involve using Linq Extension methods. Is there anyway to do it in inline linq query? *
bool? filterInclude = Convert.ToBoolean(apdvm.Filter_IncludeValue);
var a = (from e in _repository.GetAll<Entity>()
from u in e.Users
where (e.AuditQuestionGroupId != null ? e.AuditQuestionGroupId : 0) == this.LoggedInEntity.AuditQuestionGroupId
&& e.BatchNumber != null && e.BatchNumber.StartsWith(apdvm.Filter_BatchNumber == null ? "" : apdvm.Filter_BatchNumber)
&& e.Name != null && e.Name.ToLower().StartsWith(apdvm.Filter_EntityName.ToLower())
&& e.EntityState != null && e.EntityState.ToLower().Contains(apdvm.Filter_StateValue == null ? "" : apdvm.Filter_StateValue.ToLower())
&& u.NIAMembershipId != null && u.NIAMembershipId.Contains(apdvm.Filter_MemberNo == null ? "" : apdvm.Filter_MemberNo)
from p in e.PracticeProfiles.DefaultIfEmpty()
join ea in _repository.GetAll<EntityAggregate>() on e.EntityId equals ea.EntityId into eas
from ea in eas.DefaultIfEmpty()
where ea.include == filterInclude != null ? (bool)filterInclude : (true || false)
group e by new { entity = e, profile = p, ea = ea } into newGroup
orderby newGroup.Key.entity.Name
select new AggregationEntityViewModel()
{
Id = newGroup.Key.ea == null ? 0 : newGroup.Key.ea.Id,
EntityId = newGroup.Key.entity.EntityId,
Include = newGroup.Key.ea == null ? (true || false) : (bool)newGroup.Key.ea.include,
BHAddress = newGroup.Key.profile == null || newGroup.Key.profile.soloOffice == null ? false : (bool)newGroup.Key.profile.soloOffice,
Incorporated = newGroup.Key.profile == null || newGroup.Key.profile.company == null ? false : (bool)newGroup.Key.profile.company,
MajorityOwned = newGroup.Key.profile == null || newGroup.Key.profile.capital == null ? false : (bool)newGroup.Key.profile.capital,
MajorityVoting = newGroup.Key.profile == null || newGroup.Key.profile.votingRights == null ? false : (bool)newGroup.Key.profile.votingRights,
Name = newGroup.Key.entity.Name,
Partnership = newGroup.Key.profile == null || newGroup.Key.profile.partnership == null ? false : (bool)newGroup.Key.profile.partnership,
PublicAccountant = newGroup.Key.profile == null || newGroup.Key.profile.publicAccountant == null ? false : (bool)newGroup.Key.profile.publicAccountant,
Trust = newGroup.Key.profile == null || newGroup.Key.profile.operatingTrust == null ? false : (bool)newGroup.Key.profile.operatingTrust,
TrustDeed = newGroup.Key.profile == null || newGroup.Key.profile.deed == null ? false : (bool)newGroup.Key.profile.deed
}).ToList();
return a;
Convert.ToBoolean returns bool, not bool?, so there is no way filterInclude != null is true.
You should use following pattern instead of ternary operator within where clause:
var query = _repository.GetAll<Entity>();
if (apdvm.Filter_IncludeValue == "true")
query = query.Where(x => x.include == true);
else if (apdvm.Filter_IncludeValue == "false")
query = query.Where(x => x.include == false);
return query;
I assumed apdvm.Filter_IncludeValue is a string (and that's why you tried to call Convert.ToBoolean on it).
You could use
private ICollection<AggregationEntityViewModel> getEntities(
AggregationPracticeDetailsViewModel apdvm)
{
bool? filterInclude = apdvm.Filter_IncludeValue.ConvertToNullable<bool>();
var a = (from e in _repository.GetAll<Entity>()
where !filterInclude.HasValue || ea.include == filterInclude.Value
select new AggregationEntityViewModel()
{
Include = newGroup.Key.ea == null
? (true || false)
: (bool)newGroup.Key.ea.include,
}
return a;
}
just remove your (true||false) and add filterInclude == null in the where
For Nullable Value (taken from Convert string to nullable type (int, double, etc...))
public static T? ConvertToNullable<T>(this String s) where T : struct
{
try
{
return (T?)TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(s);
}
catch (Exception)
{
return null;
}
}
There is an other solution:
var query = from e in _repository.GetAll<Entity>();
if (filterInclude.HasValue)
{
// when filterInclude is null (it means **ALL**),
// do not filter otherwise - check the flag
query = query.Where(entity => entity.Include == filterInclude.Value);
}
// or one-line:
// query = query.Where(entity => filterInclude == null
// || entity.Include == filterInclude.Value);
var a = query.Select(entity => new AggregationEntityViewModel { .... });
return a;
Other problem is that Convert.ToBoolean never returns null. You should create own method to parse apdvm.Filter_IncludeValue.
In order to convert to nullable type, you colud use the generic method:
public static Nullable<T> ToNullable<T>(this string s) where T: struct
{
Nullable<T> result = new Nullable<T>();
try
{
if (!string.IsNullOrEmpty(s) && s.Trim().Length > 0)
{
TypeConverter conv = TypeDescriptor.GetConverter(typeof(T));
result = (T)conv.ConvertFrom(s);
}
}
catch { }
return result;
}
Source.
Usage:
var filterInclude = apdvm.Filter_IncludeValue.ToNullable<bool>();
You can make it easier with fluent syntax like this:
private ICollection<AggregationEntityViewModel> getEntities(AggregationPracticeDetailsViewModel apdvm)
{
var query = _repository.GetAll<Entity>();
if(apdvm.Filter_IncludeValue != 'all')
{
var value = Convert.ToBoolean(apdvm.Filter_IncludeValue);
query = query.Where(q => q.include == value)
}
return query.Select(q => new AggregationEntityViewModel {...}).ToArray();
}
no need to evaluate string to nullable bool or smth. Same as no need to do strange boolean expressions.

Checking several string for null in an if statement

Is there a better (nicer) way to write this if statement?
if(string1 == null && string2 == null && string3 == null && string4 == null && string5 == null && string6 == null){...}
Perhaps using the null-coalescing operator(??):
if((string1 ?? string2 ?? string3 ?? string4 ?? string5 ?? string6) == null){ ;}
If all strings are in a collection you can use Linq:
bool allNull = strings.All(s => s == null);
You could put all the strings in a list and use
if(listOfStrings.All(s=>s==null))
At the very least you can put it on multiple lines
if(string1 == null
&& string2 == null
&& string3 == null
&& string4 == null
&& string5 == null
&& string6 == null)
{...}
If you made a function like this:
public static bool AllNull(params string[] strings)
{
return strings.All(s => s == null);
}
Then you could call it like this:
if (AllNull(string1, string2, string3, string4, string5, string6))
{
// ...
}
Actually, you could change AllNull() to work with any reference type, like this:
public static bool AllNull(params object[] objects)
{
return objects.All(s => s == null);
}
string[] strs = new string[] { string1, string2, string3 };
if(strs.All(str => string.IsNullOrEmpty(str))
{
//Do Stuff
}
Or use strs.All(str => str == null) if you don't want to check for empty strings.
Make a IEnumerable of strings (list or array....), then you can use .All()
var myStrings = new List<string>{string1,string2,string3....};
if(myStrings.All(s => s == null))
{
//Do something
}
In case you want to check null or empty, here is another way without arrays:
if (string.Concat(string1, string2, string3, string4, string5).Length == 0)
{
//all null or empty!
}
Well, I don't know if it is nicer or better, or not, you can use IEnumerable.Any method like this;
Determines whether a sequence contains any elements.
List<string> list = new List<string>{"string1","string2","string3", "string4", "string5"};
if(list.Any(n => n == null))
{
}
And you can use Enumerable.All() method like;
Determines whether all elements of a sequence satisfy a condition.
if (Enumerable.All(new string[] { string1, string2, string3, string4, string5 }, s => s == null) )
{
Console.WriteLine("Null");
}
This should do the same:
if (string.IsNullOrEmpty(string1 + string2 + string3 + string4 + string5 + string6)){...}

Categories

Resources