Troubles with large amount of Code duplication - c#

I have a lot of methods that follow in large parts the same algorithm, and I ideally want to be able to make calls to a generic method that eliminates a lot of code duplication.
I have tons of methods like the ones below, I would optimally want to be able to just call
Save<SQLiteLocation>(itemToSave); but i have a great deal of trouble since that the methods
SQLiteConnection.Find<T> won't accept an abstract data type like T in generics.
Is there any way to get around this, if i could get it fixed i would save as many as 150 lines of code
Here's my code:
public bool SaveLocation(ILocation location, ref int primaryKey)
{
var dbConn = new SQLiteConnection (dbPath);
SQLiteLocation itemToSave = new SQLiteLocation ();
itemToSave.LocationName = location.LocationName;
itemToSave.Latitude = location.Latitude;
itemToSave.Longitude = location.Longitude;
itemToSave.PrimaryKey = location.PrimaryKey;
----------------------------------------------------------------------------------------
SQLiteLocation storedLocation = dbConn.Find<SQLiteLocation>
(x => x.PrimaryKey == location.PrimaryKey);
if (storedLocation != null)
{
dbConn.Update(itemToSave);
return true;
}
else if (storedLocation == null)
{
dbConn.Insert(itemToSave);
primaryKey = itemToSave.PrimaryKey;
return true;
}
return false;
}
And here another method see how the code in both methods below my dashed line is basically the same thing
public bool SaveInvitation(IInvitation invitation, ref int primaryKey)
{
var dbConn = new SQLiteConnection(dbPath);
SQLiteInvitation itemToSave = new SQLiteInvitation ();
itemToSave.GroupName = invitation.GroupName;
itemToSave.InviterName = invitation.InviterName;
itemToSave.ParseID = invitation.ParseID;
itemToSave.GroupParseID = invitation.GroupParseID;
itemToSave.PrimaryKey = invitation.PrimaryKey;
---------------------------------------------------------------------------------------
SQLiteInvitation storedInvitation = dbConn.Find<SQLiteInvitation>
(x => x.PrimaryKey == invitation.PrimaryKey);
if (storedInvitation != null)
{
dbConn.Update(itemToSave);
return true;
}
else if (storedInvitation == null)
{
dbConn.Insert(itemToSave);
primaryKey = itemToSave.PrimaryKey;
return true;
}
return false;
}

Shouldn't you be able to do something like this:
Note: ICommonInterface is anything that is common between any allowable classes you would want to use as T. Preferably, looking at your code, an interface or class that exposes the PrimaryKey property.
public bool SaveItem<T>(T item, ref int primaryKey) where T : ICommonInterface, new()
{
var dbConn = new SQLiteConnection(dbPath);
T storedItem = dbConn.Find<T>(x => x.PrimaryKey == item.PrimaryKey);
if (storedItem != null)
{
dbConn.Update(item);
return true;
}
else if (storedItem == null)
{
dbConn.Insert(item);
primaryKey = item.PrimaryKey;
return true;
}
return false;
}
EDIT: Added the new() constraint to the method.

For some reason it threw an not supported exception
when i used :
T storedItem = dbConn.Find<T>(x => x.PrimaryKey == item.PrimaryKey);
The code below fixed my woes though, thanks for the help everyone, I love this site!
Also i added another constraint on T seeing as T has to be a non abstract type and an interface is just that I suppose
private void SaveItem<T>(T item, ref int primaryKey)
where T : ISQLiteClass, new()
{
var dbConn = new SQLiteConnection(dbPath);
T storedItem = dbConn.Find<T>(primaryKey);
if (storedItem != null)
{
dbConn.Update(item);
}
else if (storedItem == null)
{
dbConn.Insert(item);
primaryKey = item.PrimaryKey;
}
}

Related

Having trouble with an ICollection/IEnumerable operation - won't remove an occurrence

I'm using a FastObjectListView to enter S/Ns of units to a Disposition (sold, RMA, etc) and I enter a constant for the first S/N - "(Enter Serial)"
I'm using this same model in another section of code (RMA) but I'm missing something when trying to do the same operation for Disposition.
public UnitHistory RemoveUnit(Unit unit)
{
if (unit == null)
{
return null;
}
IEnumerable<UnitHistory> seq = AssociatedUnits.Where(p => p.Unit.Equals(unit));
var unitHistories = seq.ToList();
if (unitHistories.Any())
{
List<UnitHistory> collection = new List<UnitHistory>();
collection.AddRange(AssociatedUnits);
collection.Remove(unitHistories[0]);
AssociatedUnits.Clear();
foreach (UnitHistory history in collection)
{
AssociatedUnits.Add(history);
}
unitHistories[0].Disposition = null;
DisassociatedUnits.Add(unitHistories[0]);
unitHistories[0].Unit.UnitHistory.Remove(unitHistories[0]);
return unitHistories[0];
}
return null;
}
The code won't remove unitHistories[0] from collection.
This model does work in the following code:
public RmaRepairNotes RemoveUnit(Unit unit)
{
if (unit == null)
{
return null;
}
IEnumerable<RmaRepairNotes> seq = AssociatedUnits.Where(p => p.Unit.Equals(unit));
var unitRmaHistories = seq.ToList();
if (unitRmaHistories.Any())
{
List<RmaRepairNotes> collection = new List<RmaRepairNotes>();
collection.AddRange(AssociatedUnits);
collection.Remove(unitRmaHistories[0]);
AssociatedUnits.Clear();
foreach (RmaRepairNotes note in collection)
{
AssociatedUnits.Add(note);
}
unitRmaHistories[0].Rma = null;
DisassociatedUnits.Add(unitRmaHistories[0]);
unitRmaHistories[0].Unit.RmaRepairNotes.Remove(unitRmaHistories[0]);
return unitRmaHistories[0];
}
return null;
}
AssociatedUnits is an ICollection in both classes.
EDIT - SOLUTION: I found a logic error in the Equals code of the UnitHistory class. Now it functions perfectly.
The UnitHistory Class had a logic error in the Equals function. Now that objects could be identified as being equal, the code functions perfectly.

Calling IF Statement method in C#

I have noticed that I am repeating a lot of my code. What I want to do is store the below if-statement in a method so that it can be called at any time. My problem is, I understand methods, slightly, but I'm having difficulty creating a method for what i want. Below is an example of my code. The commented out code is the code i want to put in a method.Any help is much appreciated.
if (result.Equals("") && type == "")
{
JObject jobj = JObject.Parse(Helper.callerClass(#""));
var titleTokens = jobj.SelectTokens("...title");
var values = titleTokens.Select(x => (x as JProperty).Value);
/*if (titleTokens.Contains(s))
{
MessageBox.Show("");
}
else
{
MessageBox.Show("");
}*/
}
private bool Check(string result, string type) {
if (result.Equals("") && type == "")
{
JObject jobj = JObject.Parse(Helper.callerClass(#""));
var titleTokens = jobj.SelectTokens("...title");
var values = titleTokens.Select(x => (x as JProperty).Value);
return titleTokens.Contains(s);
}
return false;
}
You mean like this ?
//To call the function use the following line and replace yourClassName with you class name
yourClassName myInstObj= new yourClassName();
myInstObj.Check(result,type);
//Copied from the above answer b/c it should work fine.
private bool Check(string result, string type) {
if (result.Equals("") && type == "")
{
JObject jobj = JObject.Parse(Helper.callerClass(#""));
var titleTokens = jobj.SelectTokens("...title");
var values = titleTokens.Select(x => (x as JProperty).Value);
if (titleTokens.Contains(s))
{
return true;
}
else
{
return false;
}
}
}

MVC6 Custom IModelBinder, Beta8 changed?

I have this custom IModelBinder that was working, but i have since uninstalled beta5 and beta7, so i am using the latest beta8. It appears that the code has completely changed and i cant seem to find any vNext code on github to see the changes.
Can someone please tell me how to update this to work with beta8, or give me a URL to the source code on github?
public class CommaDelimitedArrayModelBinder : IModelBinder
{
public async Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
{
var key = bindingContext.ModelName;
var val = bindingContext.ValueProvider.GetValue(key);
var result = new ModelBindingResult(null, key, false);
if (val != null)
{
var s = val.FirstValue;
if (s != null)
{
var elementType = bindingContext.ModelType.GetElementType();
var converter = TypeDescriptor.GetConverter(elementType);
var values = Array.ConvertAll(s.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries),
x => { return converter.ConvertFromString(x != null ? x.Trim() : x); });
var typedValues = Array.CreateInstance(elementType, values.Length);
values.CopyTo(typedValues, 0);
result = new ModelBindingResult(typedValues, key, true);
}
else
{
// change this line to null if you prefer nulls to empty arrays
result = new ModelBindingResult(Array.CreateInstance(bindingContext.ModelType.GetElementType(), 0), key, true);
}
}
return result;
}
}
The only error i have is that ModelBindResult does not take any constructor parameters and all the parameters are readonly, so they cant be set? So how am i supposed to return a ModelBindingResult, if i cant set any properties on it?
The source code for ModelBindingResult in beta 8 is here. It has static methods that take arguments and return a new instance, for example:
public static ModelBindingResult Success(string key, object model)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
return new ModelBindingResult(key, model, isModelSet: true);
}

Search function LINQ. Use checkbox values as parameters

I have a search function that tales 7 parameters and 6 of them are checkbox values. They are bools like shown down below. I Have a problem with my datetime search. If the user check that box if would like do run a serach function where that a date is not null in the database. My code look like this at the moment. But i would like to get some feedback to how to improve my code for better performance and code structure.
public List<Invoice> GetAllInvoicesBySearch(int merchant, long buyer, bool send, bool paid, bool firstReminder, bool secondReminder, bool invoiceClaim)
{
var sendValue = new InvoiceStatus();
var paidValue = new InvoiceStatus();
var firstRemind = new DateTime();
var secondRemind = new DateTime();
if (buyer <= 0)
{
return null;
}
if (send)
{
sendValue = InvoiceStatus.Sent;
}
if (paid)
{
paidValue = InvoiceStatus.Paid;
}
if (firstReminder)
{
firstRemind = DateTime.Now;
}
if (secondReminder)
{
secondRemind = DateTime.Now;
}
return
Context.Invoices.Where(
i =>
i.InstallationId == merchant && i.Buyer.Msisdn == buyer || i.Status == sendValue || i.Status == paidValue ||
i.FirstReminderDate == firstRemind || i.SecondReminderDate == secondRemind).ToList();
}
So my problem is with the datetime at the moment to get that correctly. Any suggestions on how to solve my problem and improve my code?
You would be better off using a PredicateBuilder and converting to an extension method like this:
public static class ExtensionMethods {
public static IQueryable<Invoice> Search(this IQueryable<Invoice> src, int merchant,
long buyer, bool send, bool paid, bool firstReminder,
bool secondReminder, bool invoiceClaim)
{
var predicate = PredicateBuilder.False<Invoice>();
var sendValue = new InvoiceStatus();
var paidValue = new InvoiceStatus();
var firstRemind = new DateTime();
var secondRemind = new DateTime();
if (buyer <= 0)
{
return src.Where(predicate);
}
predicate=predicate.Or(i=>i.InstallationId == merchant && i.Buyer.Msisdn == buyer);
if (send)
{
predicate=predicate.Or(i=>i.Status == InvoiceStatus.Sent);
}
if (paid)
{
predicate=predicate.Or(i=>i.Status == InvoiceStatus.Paid);
}
if (firstReminder)
{
predicate=predicate.Or(i=>i.FirstReminderDate == DateTime.Today);
}
if (secondReminder)
{
predicate=predicate.Or(i=>i.SecondReminderDate == DateTime.Today);
}
return src.Where(predicate);
}
}
Also, if I understand your code correctly, InvoiceStatus should either be an enum, or at the very least, InvoiceStatus.Sent and InvoiceStatus.Paid should be marked as being static. Reference it like so:
Context.Invoices.Search(...).OrderBy(...)...
It will make further manipulation much easier if you need to do sorting, paging, filtering beyond the original searching.

Generic extension method for retrieving 'default' value?

I'm playing around a bit with determining the default values of objects, based on the example here:
https://stackoverflow.com/a/3195792/1293496
This particular extension method was created for System.Type. What I was trying to accomplish was to make this even more generic, where I could do something like this:
int i = 3;
bool amIaDefaultValue = i.IsDefaultValue();
I would expect this to return true if i == 0 (the default value for an int), and false for all other instances.
Here is my initial attempt:
public static bool IsDefaultValue<T>(this T value)
{
var t = typeof(T); // always comes back as object..?
if (t.IsValueType && Nullable.GetUnderlyingType(t) == null)
{
return value.Equals(Activator.CreateInstance<T>());
}
else
{
var defaultValue = default(T);
if (value == null)
return defaultValue == null;
else
return value.Equals(defaultValue);
}
}
On the plus side, I'm able to attach .IsDefaultValue() to any object. Unfortunately, the type of T always comes back as System.Object. I can get the correct type if I set it up this way:
var t = typeof(value);
But if the value happens to be null, I'll get an error straight away. Is there a good workaround for implementing an extension method like this? Or should I stick to the tried and tested route from the example?
Edit
As pointed out by comments, it seems I oversimplified this a bit and missed the root of the problem. Here's what was actually calling my IsDefaultValue():
foreach (var imprintProperty in deltas.GetType().GetProperties())
{
var value = imprintProperty.GetValue(deltas);
if (!value.IsDefaultValue())
{
// get corresponding prop in programmable area
var programmableProp = progarea.GetType().GetProperty(imprintProperty.Name);
if (programmableProp != null)
programmableProp.SetValue(progarea, value);
}
}
And now it becomes obvious that .GetValue is always returning as System.Object. Uff.
Is it still possible to treat the object as its underlying type in the extension method? Sorry for the confusion with this.
Take a look at this:
static class Program
{
static void Main()
{
int a = 1;
Console.WriteLine("a.IsDefaultValue() : " + a.IsDefaultValue());
a = 0;
Console.WriteLine("a.IsDefaultValue() : " + a.IsDefaultValue());
object obj = new object();
Console.WriteLine("obj.IsDefaultValue() : " + obj.IsDefaultValue());
obj = null;
Console.WriteLine("obj.IsDefaultValue() : " + obj.IsDefaultValue());
int? b = 1;
Console.WriteLine("b.IsDefaultValue() : " + b.IsDefaultValue());
b = null;
Console.WriteLine("b.IsDefaultValue() : " + b.IsDefaultValue());
Console.ReadKey(true);
}
static bool IsDefaultValue<T>(this T value)
{
if (ReferenceEquals(value, null))
{
return true;
}
var t = value.GetType();
if (t.IsValueType)
{
return value.Equals(Activator.CreateInstance(value.GetType()));
}
return false;
}
}
Apparently works (I've to say that I was convinced that the other way should have worked but not)

Categories