I have a public function that queries against a specific entity. I would like to replicate the function for any table I pass in but don't know how. Here is the working function I want to make dynamic:
public string MaxDepartment()
{
CPLinkEntities _context = new CPLinkEntities();
results = _context.LOG_Departments.Max(t => t.LastUpdated); // hard coded
string hex = BitConverter.ToString(results);
hex = hex.Replace("-", "");
return hex;
}
What I would really like to do here is pass in an entity to query against. All entities have a timestamp. Here is what I envision it would look like but doesn't work:
public string MaxDepartment(CPLinkEntities tableName)
{
var results = tableName.Max(t => t.LastUpdated);
string hex = BitConverter.ToString(results);
hex = hex.Replace("-", "");
return hex;
}
Calling the function from controller then would be:
CPLinkEntities context = new CPLinkEntities();
var tableName = context.LOG_Departments;
var maxDept = cf.MaxDepartment(tableName);
The easiest way to do it without changing any of your existing classes (if you can, see Oleksii's answer) is to manually create the expression tree and have it select the property you want.
public static string MaxDepartment<U>(IQueryable<U> table)
{
var parameter = Expression.Parameter(typeof(U));
var property = Expression.Property(parameter, "LastUpdated");
var lambada = Expression.Lambda<Func<U, byte[]>>(property, parameter);
var results = table.Max(lambada);
string hex = BitConverter.ToString(results);
hex = hex.Replace("-", "");
return hex;
}
You would call it via
using(CPLinkEntities _context = new CPLinkEntities()) //You forgot to dispose in your original example
{
var max = MaxDepartment(_context.LOG_Departments);
//Do whatever you want with max here.
}
This will fail at runtime if you try to pass in a table that does not have a LastUpdated property.
I think you should mark your entity with an interface like this:
public interface ILastUpdatable
{
byte[] LastUpdated {get;set;}
}
public partial class LOG_Departments : ILastUpdatable
{
}
and then make your method expecting an object of type that implements an interface like this:
public string MaxDepartment<TLastUpdatable>(IQueryable<TLastUpdatable> updatables)
where TLastUpdatable : class, ILastUpdatable
{
var results = updatables.Max(t => t.LastUpdated);
string hex = BitConverter.ToString(results);
hex = hex.Replace("-", "");
return hex;
}
UPDATE:
Also you would consider to use it as extension method:
public static class MaxUpdatableExtensions
{
public static string MaxDepartment<TLastUpdatable>(this IQueryable<TLastUpdatable> updatables)
where TLastUpdatable : class, ILastUpdatable
{
var results = updatables.Max(t => t.LastUpdated);
string hex = BitConverter.ToString(results);
hex = hex.Replace("-", "");
return hex;
}
}
and call it like this:
CPLinkEntities _context = new CPLinkEntities();
var results = _context.LOG_Departments.MaxDepartment();
Related
How may I store an array of Xamarin.Forms.Point in an SQLite database?
I have the following method:
async void OnSaveButtonClicked(object sender, EventArgs e)
{
var temp = padView.Points;
var tempArray = padView.Points.ToArray();
var databaseItem = new DatabaseItem
{
Name = Name.Text,
Date = Date.Date.ToString(),
//PadViewPoints =
};
//var databaseItem = (DatabaseItem)BindingContext;
await App.Database.SaveItemAsync(databaseItem);
await Navigation.PopAsync();
}
Given there is a signature on the padView, when stepping through the aforementioned method, I see that tempArray has a value of Xamarin.Forms.Point[76].
I'd like to store this array of points in the database so that I may load it later when loading the item.
As Jason said, you could store it as a string, a practical implementation of that would be:
var temp = padView.Points;
var tempArray = padView.Points.ToArray();
var databaseItem = new DatabaseItem
{
Name = Name.Text,
Date = Date.Date.ToString(),
PadViewPointsString = JsonConvert.SerializeObject(tempArray)
};
And in the DatabaseItem class:
public class DatabaseItem
{
// All other properties
string padViewPointsString;
public string PadViewPointsString
{
get => padViewPointsString;
set
{
padViewPointsString = value;
PadViewPoints = JsonConvert.DeserializeObject<Xamarin.Forms.Point[]>(value);
}
}
public Xamarin.Forms.Point[] PadViewPoints { get; set; }
}
This will make the class deserialize the string every time you set it's value (e.g. when you get it from the serialized database).
Obs. This example is using Newtonsoft.Json library
Hope this helps! :)
I've posted a similar question (and answered) previously but I've realised I still have a missing piece of the puzzle when passing a method into another method. My question is when passing a method as a parameter how can you include parameters? I've included an example below.
Any help much appreciated.
Many thanks,
Service call
private readonly MemberRepo _memberRepo;
public SomeService()
{
_memberRepo = new MemberRepo();
}
public string GetMembers(int id)
{
// This works, i.e. the RunMethod internally calls the Get method on the repo class - problem: how can I pass the id into the repo Get method?
var result = RunMethod(_memberRepo.Get);
...
return stuff;
}
private string RunMethod(Func<int, string> methodToRun)
{
var id = 10; // this is a hack - how can I pass this in?
var result = methodToRun(id);
..
}
Repository
public class MemberRepo
{
public string Get(int id)
{
return "Member from repository";
}
}
Update
private string RunMethod(Func<int, string> methodToRun)
{
if(id.Equals(1))
{
// Do something
//
var result = methodToRun(id);
..
}
Just pass a second argument to the RunMethod method:
private string RunMethod(Func<int, string> methodToRun, int id)
{
var result = methodToRun(id);
..
}
You can always make id have an optional input as well if needed:
int id= 10
You can pass a lambda function that performs whatever actions you want:
var result = RunMethod(_ => _memberRepo.Get(10));
This makes the int part of the method signature pretty meaningless, so if you have the ability to change your RunMethod() signature, you can do this:
private string RunMethod(Func<string> methodToRun)
{
var result = methodToRun();
..
}
then this:
var result = RunMethod(() => _memberRepo.Get(10));
Update if you need to be able to access the parameter within your RunMethod() method, then just pass it as a separate parameter as TheLethalCoder suggests:
private string RunMethod(Func<int, string> methodToRun, int id)
{
if(id.Equals(1))
{
// Do something
//
var result = methodToRun(id);
..
}
and
var result = RunMethod(memberRepo.Get, 10);
How to Convert var to string?
In my windowsphone application page, i want to convert this var DemoHeader to a string.
XDocument myData = XDocument.Load("aarti.xml");
var DemoHeader = from query in myData.Descendants("bookinfo")
select new HeaderT
{
Header = (string)query.Element("header")
};
ContentHeaderLine.Text = DemoHeader.ToString(); //LINE GIVING WRONG DATA
public class HeaderT
{
string header;
public string Header
{
get { return header; }
set { header = value; }
}
}
How can i convert var DemoHeader to a string?
First, var is not a type by itself, the type will be inferred from the value by the compiler. Your type is actually HeaderT and your query returns an IEnumerable<HeaderT> (so possibly multiple).
Presuming you want the first header:
HeaderT first = DemoHeader.First();
string firstHeader = first.Header();
or you want all returned separated by comma:
string allHeaders = String.Join(",", DemoHeader.Select(dh => dh.Header()));
If you want that ToString returns something meaningful(instead of name of the type), override it:
public class HeaderT
{
private string header;
public string Header
{
get { return header; }
set { header = value; }
}
public override string ToString()
{
return Header;
}
}
Override ToString() in HeaderT class could help. After that, you DemoHeader variable is a list of HeaderT not a single HeaderT.
I have an immutable struct and would like to keep it immutable, but also allow schematics like var p2 = p1.v = 3. I thought that the following might work, but it appears not:
public struct Number {
readonly int n;
public int N {
get{ return n; }
set{ return new Number(value); }
}
public Number(int newN) {
n = newN;
}
}
Is there any way to get var p2 = p1.v = 3 or var p2 = (p1.v = 3) to work?
No, there is no syntax like this that will work. Setters are, well, setters, not a way to get something.
First of all you want to do something that no one will be able to read. If you structure is immutable what one should expect as result of p1.v = 3? Obviously p1 should not change, no one expect setter to return value... the only reasonable behavior would be to see an exception "This object is immutable", but than lack of setter would be much better indication of the property being read only....
Possibly you trying to implement something like fluent interface which is much more common:
var newValue = oldValue.WithOneProperty(5).WithOtherProperty(3);
class Number
{
int oneProperty;
int otherProperty;
Number WithOneProperty(int v) { return new Number(v, this.otherProperty); }
Number WithOtherProperty(int v) { return new Number(this.oneProperty, v); }
}
You should only return values from getters.
I think there is a valid use for this with one-time-tokens or keys. I used some of the code here to generate this:
public class MyController : Controller
{
private static string m_oneTimeKey = "this key hasn't been initialised yet";
private string oneTimeKeyGet()
{
// Return the last key
string returnValue = MyController.m_oneTimeKey;
// Generate a new random key so the one we return can't be reused
var m_oneTimeKey = GetRandomString();
return returnValue;
}
private string oneTimeKeySet()
{
// Generate a new random key
var newValue = GetRandomString();
m_oneTimeKey = newValue;
return newValue;
}
private string GetRandomString()
{
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var random = new Random();
var returnValue = new string(
Enumerable.Repeat(chars, 8)
.Select(s => s[random.Next(s.Length)])
.ToArray());
return returnValue;
}
And then I use it with:
var myURL = "/Index?id=" + ID + "&key=" + oneTimeKeySet();
And within the ActionResult I can verify if this is the one time call with:
public ActionResult Index(Guid id, string key)
{
if (key == oneTimeKeyGet() {
....
}
}
}
I've actually gone a step further and I also have a static key that is passed between functions that is also checked for in the if in the ActionResult.
Is it possible to make a template for SELECT in a LINQ query? Right now I have 6 methods that uses the exact same SELECT, i would like to use a template if possible.
This is the code I'm using, when I want to make a change to the select I have to change the same thing at so many places in my code.
result = query.Select(b => new
{
route_id = b.b.route_id,
name = b.b.name,
description = b.b.description,
distance = b.b.distance,
distance_to_route = (int)b.distance_to_from_me,
departure_place = b.b.departure_place,
arrival_place = b.b.arrival_place,
owner = b.b.user.username,
average_rating = b.avg_rating,
is_favorite = b.is_favorite,
date = b.b.date,
attributes = b.b.route_attributes.Select(c =>
c.route_attribute_types.attribute_name),
coordinates = b.b.coordinates.Select(c =>
new coordinateToSend { sequence = c.sequence,
lat = c.position.Latitude,
lon = c.position.Longitude })
});
Here is a simple example of one way you could do this:
In your example, you're converting the source type to an anonymous type. You could create a class to represent your converted/result type, for example:
public class ResultClass
{
public string ResultPropA { get; set; }
}
For examples sake, lets say the following was the definition of your source class:
public class SourceClass
{
public string SourcePropA { get; set; }
}
Now that you have type definitions for your source and result objects, you can create an extension method to convert a collection of your source class to a collection of your result class:
public static class SourceToResultRepository
{
public static IEnumerable<ResultClass> ConvertSourceToResult
(this IEnumerable<SourceClass> source)
{
return source.Select(s => new ResultClass
{
ResultPropA = s.SourcePropA
//Add all other property transformations here
});
}
}
And here is an example of how you could use it wherever you need to perform the transformation:
//Extension usage:
var result = Database.Source.ConvertSourceToResult();
//Direct usage:
var result = SourceToResultRepository.ConvertSourceToResult(Database.Source);