Switch Statement To Dynamic for filling in parameters - c#

I am trying to create a more dynamic approach to pulling data for a view than a switch statement. Right now I have several different options and more could be added anytime. The tables that will be pulled from are all the same in format except for the name of the table and the name of their ID field.
public List<listoftables> BuildListOfTables(string router)
{
var listOfViewModels = new List<FormatOfTables>();
using var context = new TableContext();
switch (router)
{
case "firstTable":
listOfViewModels = context.Set<firstTable>().Select(x => new FormatOfTables
{
UniqueID = x.FirstTableID,
Value = x.Value,
}).ToList();
break;
case "secondTable":
listOfViewModels = context.Set<secondTable>().Select(x => new FormatOfTables
{
UniqueID = x.SecondTableID,
Value = x.Value,
}).ToList();
break;
case "thirdTable":
listOfViewModels = context.Set<ThirdTable>().Select(x => new FormatOfTables
{
UniqueID = x.ThirdTableID,
Value = x.Value,
}).ToList();
break;
return listOfViewModels;
}
I'm trying to find a way to do this more dynamically. So as long as the option in router matches a table name, each table that gets put into the model just fills the UniqueID and Value to be whatever their ID and value happens to be rather than having to match the column names. So if a fourth table came in I would only have to worry about if router matched the table name rather than having to add an entirely new switch per entry.

The tables that will be pulled from are all the same in format except for the name of the table and the name of their ID field.
The problem here is passing the typename to the Set<T>() function. But we'll get to that. First, let's make some of this easier by adding an interface:
public interface IMyTable
{
string TableName {get;}
int UniqueID {get;}
}
Then each of your firstTable, secondTable, ThirdTable types must implement this interface:
public class firstTable : IMyTable
{
// existing class stuff here
public int UniqueID { get { return FirstTableId;} }
public string TableName { get { return "FirstTable"; } }
}
And now the method can look like this:
public IEnumerable<listoftables> BuildListOfTables(string router)
{
using var context = new TableContext();
DBSet tableSet = null; //I'm making an assumption about the Set() function here. You may need to change the type.
switch (router)
{
case "firstTable":
tableSet = context.Set<firstTable>();
break;
case "secondTable":
tableSet = context.Set<secondTable>();
break;
case "thirdTable":
tableSet = context.Set<ThirdTable>();
break;
}
if (tableSet != null)
{
return tableSet.Select(x => new FormatOfTables
{
UniqueID = x.UniqueID,
Value = x.Value
});
}
return null;
}
This reduces the repeated boilerplate down to just as much as is necessary to call the generic Set<>() function.
From here we can further reduce the code by changing how the function is designed, including how you expect to call it:
public IEnumerable<listoftables> BuildListOfTables<T>() where T : IMyTable
{
using var context = new TableContext();
return context.Set<T>()
.Select(x => new FormatOfTables
{
UniqueID = x.UniqueID,
Value = x.Value
});
}
But all this really does is push where you have to put the switch() statement up to the call site. However, that might be worth it if the call site happens to have the type information already available.
Note for ALL of these examples I converted the method to return IEnumerable instead of a List. Calling .ToList() can be notoriously bad for performance. If you really need a list (hint: you usually don't) you can still put the ?.ToList() after the function call. You might be able to improve things even further in this case by returning IQueryable, which could let later code continue the expression tree before executing anything on the server.

Related

Replace property values in a class from List<Dictionary> values

I have a method that takes a List<Dictionary<string,object>> as a parameter. The plan is to use that parameter, but only update the values held in a particular class. Here is the (partially written) method
public async Task<Errors> UpdatePageForProject(Guid projectId, List<Dictionary<string, object>> data)
{
if (!IsValidUserIdForProject(projectId))
return new Errors { ErrorMessage = "Project does not exist", Success = false };
if (data.Count == 0)
return new Errors { ErrorMessage = "No data passed to change", Success = false };
var page = await _context.FlowPages.FirstOrDefaultAsync(t => t.ProjectId == projectId);
foreach (var d in data)
{
}
return new Errors { Success = true };
}
My original plan is to take each dictionary, check if the key and the property in page match and then alter the value (so I can pass in 1 dictionary or 8 dictionaries in the list and then alter page to save back to my entity database).
I'd rather not use reflection due to the speed hit (though C#9 is really fast, I'd still rather not use it), but I'm not sure how else this can be done. I did consider using AutoMapper to do this, but for now would rather not (it's a PoC, so it is possibly overkill)
If you want to do this without Reflection (which I agree is a good idea, not just for performance reasons) then you could use a "map" or lookup table with actions for each property.
var map = new Dictionary<string,Action<Page,object>>()
{
{ "Title", (p,o) => p.Title = (string)o },
{ "Header", (p,o) => p.Field1 = (string)o },
{ "DOB", (p,o) => p.DateOfBirth = (DateTime)o }
};
You can then iterate over your list of dictionaries and use the map to execute actions that update the page.
foreach (var dictionary in data)
{
foreach (entry in dictionary)
{
var action = map[entry.Key];
action(page, entry.Value);
}
}

Select query from db using linq

I have a entity class called
[Serializable]
Public sealed class LayEntity : EntityBase
{
Public string Name {get;set;} // Getting mapped to the same column name in db table
}
In my .cs file I have a query as :
LayEntity lay = null;
Using(var context = new DBContext())
{
lay = context.LayTable.where(x=>x.id >1).Select (y=>y.Name).FirstOrDefault();
}
My intention is to store retrieve the name filed on to the entityclass.
But I am getting a compile time error as ‘Cannot implicitly convert string to Entity’.What is that I need to do?
You can most probably do this:
lay = context.LayTable
.Where(x=>x.id >1)
.Select (y=>new LayEntity (){Name=y.Name})
.FirstOrDefault();
Or this:
lay = context.LayTable.where(x=>x.id >1).FirstOrDefault();
Or even this:
lay = context.LayTable.FirstOrDefault(x=>x.id >1);
If you expect a single value I would do this:
lay = context.LayTable.SingleOrDefault(x=>x.id >1);
Error message is clear, you cannot assign string value to object of type LayEntity
Probably, what you need is
LayEntity lay = null;
Using(var context = new DBContext())
{
lay = context.LayTable.FirstOrDefault(x=>x.id >1);
if(lay != null)
{
lay.Name; // use name here.
}
}
Note, I've removed Where method as it is redundant in this case.

Updating entire node with mutating cypher in Neo4jclient

I need to update all the properties of a given node, using mutating cypher. I want to move away from Node and NodeReference because I understand they are deprecated, so can't use IGraphClient.Update. I'm very new to mutating cypher. I'm writing in C#, using Neo4jclient as the interface to Neo4j.
I did the following code which updates the "Name" property of a "resunit" where property "UniqueId" equals 2. This works fine. However,
* my resunit object has many properties
* I don't know which properties have changed
* I'm trying to write code that will work with different types of objects (with different properties)
It was possible with IGraphClient.Update to pass in an entire object and it would take care of creating cypher that sets all properies.
Can I somehow pass in my object with mutating cypher as well?
The only alternative I can see is to reflect over the object to find all properties and generate .Set for each, which I'd like to avoid. Please tell me if I'm on the wrong track here.
string newName = "A welcoming home";
var query2 = agencyDataAccessor
.GetAgencyByKey(requestingUser.AgencyKey)
.Match("(agency)-[:HAS_RESUNIT_NODE]->(categoryResUnitNode)-[:THE_UNIT_NODE]->(resunit)")
.Where("resunit.UniqueId = {uniqueId}")
.WithParams(new { uniqueId = 2 })
.With("resunit")
.Set("resunit.Name = {residentialUnitName}")
.WithParams(new { residentialUnitName = newName });
query2.ExecuteWithoutResults();
It is indeed possible to pass an entire object! Below I have an object called Thing defined as such:
public class Thing
{
public int Id { get; set; }
public string Value { get; set; }
public DateTimeOffset Date { get; set; }
public int AnInt { get; set; }
}
Then the following code creates a new Thing and inserts it into the DB, then get's it back and updates it just by using one Set command:
Thing thing = new Thing{AnInt = 12, Date = new DateTimeOffset(DateTime.Now), Value = "Foo", Id = 1};
gc.Cypher
.Create("(n:Test {thingParam})")
.WithParam("thingParam", thing)
.ExecuteWithoutResults();
var thingRes = gc.Cypher.Match("(n:Test)").Where((Thing n) => n.Id == 1).Return(n => n.As<Thing>()).Results.Single();
Console.WriteLine("Found: {0},{1},{2},{3}", thingRes.Id, thingRes.Value, thingRes.AnInt, thingRes.Date);
thingRes.AnInt += 100;
thingRes.Value = "Bar";
thingRes.Date = thingRes.Date.AddMonths(1);
gc.Cypher
.Match("(n:Test)")
.Where((Thing n) => n.Id == 1)
.Set("n = {thingParam}")
.WithParam("thingParam", thingRes)
.ExecuteWithoutResults();
var thingRes2 = gc.Cypher.Match("(n:Test)").Where((Thing n) => n.Id == 1).Return(n => n.As<Thing>()).Results.Single();
Console.WriteLine("Found: {0},{1},{2},{3}", thingRes2.Id, thingRes2.Value, thingRes2.AnInt, thingRes2.Date);
Which gives:
Found: 1,Foo,12,2014-03-27 15:37:49 +00:00
Found: 1,Bar,112,2014-04-27 15:37:49 +00:00
All properties nicely updated!

Map enum value robustly

I have a form where I collect data from users. When this data is collected, I pass it to various partners, however each partner has their own rules for each piece of data, so this has to be converted. I can make this happen, but my worries are about the robustness. Here's some code:
First, I have an enum. This is mapped to dropdown a dropdown list - the description is the text value, and the int mapped to the value.
public enum EmploymentStatusType
{
[Description("INVALID!")]
None = 0,
[Description("Permanent full-time")]
FullTime = 1,
[Description("Permanent part-time")]
PartTime = 2,
[Description("Self employed")]
SelfEmployed = 3
}
When the form is submitted, the selected value is converted to its proper type and stored in another class - the property looks like this:
protected virtual EmploymentStatusType EmploymentStatus
{
get { return _application.EmploymentStatus; }
}
For the final bit of the jigsaw, I convert the value to the partners required string value:
Dictionary<EmploymentStatusType, string> _employmentStatusTypes;
Dictionary<EmploymentStatusType, string> EmploymentStatusTypes
{
get
{
if (_employmentStatusTypes.IsNull())
{
_employmentStatusTypes = new Dictionary<EmploymentStatusType, string>()
{
{ EmploymentStatusType.FullTime, "Full Time" },
{ EmploymentStatusType.PartTime, "Part Time" },
{ EmploymentStatusType.SelfEmployed, "Self Employed" }
};
}
return _employmentStatusTypes;
}
}
string PartnerEmploymentStatus
{
get { return _employmentStatusTypes.GetValue(EmploymentStatus); }
}
I call PartnerEmploymentStatus, which then returns the final output string.
Any ideas how this can be made more robust?
Then you need to refactor it into one translation area. Could be something like a visitor pattern implementation. Your choices are distribute the code (as you are doing now) or visitor which would centralize it. You need to build in a degree of fragility so your covering tests will show problems when you extend in order to force you to maintain the code properly. You are in a fairly common quandry which is really a code organisational one
I did encounter such a problem in one of my projects and I solved it by using a helper function and conventions for resource names.
The function is this one:
public static Dictionary<T, string> GetEnumNamesFromResources<T>(ResourceManager resourceManager, params T[] excludedItems)
{
Contract.Requires(resourceManager != null, "resourceManager is null.");
var dictionary =
resourceManager.GetResourceSet(culture: CultureInfo.CurrentUICulture, createIfNotExists: true, tryParents: true)
.Cast<DictionaryEntry>()
.Join(Enum.GetValues(typeof(T)).Cast<T>().Except(excludedItems),
de => de.Key.ToString(),
v => v.ToString(),
(de, v) => new
{
DictionaryEntry = de,
EnumValue = v
})
.OrderBy(x => x.EnumValue)
.ToDictionary(x => x.EnumValue, x => x.DictionaryEntry.Value.ToString());
return dictionary;
}
The convention is that in my resource file I will have properties that are the same as enum values (in your case None, PartTime etc). This is needed to perform the Join in the helper function which, you can adjust to match your needs.
So, whenever I want a (localized) string description of an enum value I just call:
var dictionary = EnumUtils.GetEnumNamesFromResources<EmploymentStatusType>(ResourceFile.ResourceManager);
var value = dictionary[EmploymentStatusType.Full];

Least code to convert one object to anothe for both single object and List<object>?

I need to convert one object to another...in both cases of a single instance of the object as well as corresponding Lists of those objects. I'd rather not have to perform the same mappings in 2 places. Here is what I mean:
This converts a Facebook movie to a Standard Movie object
//Converts an Facebook object to a Standard Movie object
public MovieDetails ConvertFacebookMovieToStandardMovie(FacebookMovie Movies)
{
MovieDetails objMovieDetails = new MovieDetails();
objMovieDetails.ID = 0;
objMovieDetails.Source = Movies.Source;
objMovieDetails.SourceID = Convert.ToString(Movies.ID);
objMovieDetails.Title = Movies.Name;
objMovieDetails.URL = GetInternalMovieURL(objMovieDetails.Source, objMovieDetails.SourceID);
objMovieDetails.ImageURL = Movies.Picture;
objMovieDetails.SourceURL = Movies.SourceURL;
objMovieDetails.Description = Movies.Description
return objMovieDetails;
}//Convert Facebook to standard
Now I also need to do the same things in cases where I have the same objects, just in List form, i.e.
//Converts an Facebook class to a MovieDetails class of WWN
public List<MovieDetails> ConvertFacebookMovieToStandardMovie(List<FacebookMovie> lstFacebookMovieDetails)
{
List<MovieDetails> lstMovieListDetails = lstFacebookMovieDetails.Select(Movies => new MovieDetails()
{
ID = 0
,Source = Movies.Source
,SourceID = Convert.ToString(Movies.ID)
,Title = Movies.Name
,URL = GetInternalMovieURL(Source, SourceID)
,ImageURL = Movies.Picture
,SourceURL = Movies.SourceURL
,Description = Movies.Description
}).ToList();
return lstMovieListDetails;
}//Convert Facebook to standard
I'm new to c# and linq, so not sure how I could create one method that could handle both...or at least a way to encapsulate the mappings.
I know I could create an overload method for the List scenario and loop through the items in the list and call the first object convert method...But I was hoping to use the linq route I currently have for, what I'm guessing, is better performance.
Thanks!
Chad
Just call your function.
public List<MovieDetails> ConvertFacebookMovieToStandardMovie(List<FacebookMovie> lstFacebookMovieDetails)
{
List<MovieDetails> lstMovieListDetails =
lstFacebookMovieDetails.Select(Movies => ConvertFacebookMovieToStandardMovie(Movies)).ToList();
return lstMovieListDetails;
}
or the other way
public MovieDetails ConvertFacebookMovieToStandardMovie(FacebookMovie Movies)
{
return ConvertFacebookMovieToStandardMovie(new [] { Movies} ).FirstOrDefault();
}//Convert Facebook to standard
You could also overload as then
public static MovieDetails operator as(FacebookMovie m)
{
if (m == null) return null;
MovieDetails objMovieDetails = new MovieDetails()
{
ID = 0,
Source = Movies.Source,
SourceID = Convert.ToString(Movies.ID),
Title = Movies.Name,
URL = GetInternalMovieURL(objMovieDetails.Source, objMovieDetails.SourceID),
ImageURL = Movies.Picture,
SourceURL = Movies.SourceURL,
Description = Movies.Description
}
return objMovieDetails
}
then ConvertFacebookMovieToStandardMovie seems silly but it would look like this:
public MovieDetails ConvertFacebookMovieToStandardMovie(FacebookMovie Movies)
{
return Movies as MovieDetails;
}//Convert Facebook to standard
and
public List<MovieDetails> ConvertFacebookMovieToStandardMovie(List<FacebookMovie> lstFacebookMovieDetails)
{
List<MovieDetails> lstMovieListDetails =
lstFacebookMovieDetails.Select(Movies => Movies as MovieDetails).ToList();
return lstMovieListDetails;
}
Unless there's a performance gain on having separate code for these two cases I'd simply scrap the single movie variant and keep the List variant. To do the single movie variant simply do this with using System.Linq;:
List<FacebookMovie> moviesDetailsList = ...
MovieDetails movieDetails = ConvertFacebookMovieToStandardMovie(moviesDetailsList).Single();
If you want the single case as a separate method, you can place the above as the body of that method with "..." = new [] {movieDetail};
A shorter version
public List<MovieDetails> ConvertFacebookMovieToStandardMovie(List<FacebookMovie> lstFacebookMovieDetails)
{
return lstFacebookMovieDetails.ConvertAll(ConvertFacebookMovieToStandardMovie);
}
As per msdn
Converts the elements in the current List to another type, and returns a list containing the converted elements.

Categories