I am trying to retrieve all entities of type Queried from the database where Referenced property or it's ancestor for which its label (meaning referenced.Parent.ChildLabel) is equal to some given label value exampleLabel, has an Id equal to exampleId.
I tried using:
var result = nhibernateSession
.Query<Queried>()
.Where(queried => queried.SelfReferencing.GetSelfOrAncestor("exampleLabel") == exampleId)
.ToList();
but it throws a "System.NotSupportedException", probably because it does not know how to translate the GetSelfOrAncestor into SQL.
The method GetSelfOrAncestor(string label) returns the Id of the SelfReferencing instance on which it was called or it's ancestor which meets the condition that this.Parent.ChildLabel is equal to exampleLabel, otherwise returns 0.
For example, in the following diagram if queried.SelfReferencing would point to the one at Level 2, GetSelfOrAncestor("exampleLabel") would return the Id of the object at Level 1.
http://j.mp/Xl86OP
public class Queried
{
public int Id { get; set; }
public SelfReferencing Referenced { get; set; }
}
public class SelfReferencing
{
public SelfReferencing Parent { get; set; }
private IList<SelfReferencing > children = new List<SelfReferencing >();
public virtual IList<SelfReferencing > Children
{
get
{
return children;
}
set
{
children = value;
}
}
public string ChildLabel { get; set; }
}
Any help on how to achieve this would be highly appreciated :)
To achieve what you want, I would provide a method in SelfReferencing that does the search for the label through the object graph.
Should be something like this: (Warning, not tested yet!)
public bool ContainsLabel(string label)
{
if (this.ChildLabel.Equals(label))
{
return true;
}
else
{
foreach (var child in Children)
{
return child.ContainsLabel(label);
}
}
return false;
}
You can use it then as follows:
var result = nhibernateSession
.Query<Queried>()
.Where(queried => queried.SelfReferencing.ContainsLabel("exampleLabel"))
.ToList();
Edited for more convenience in reading.
Related
I've a class with Tree hierarchy as below. I need to set Leaf node to status "InProgress". Then All ancestors needs to have change from NotStarted to InProgress. And if all leaf nodes were Complete, it immediate parent status need to be Complete. Is there a quick way to do it other than recursively iterating multiple times?
pubic class Node
{
public string Name { get; set; }
public List<Node> Children { get; set; } = new List<Node>();
public int NodeStatus {get; set;} // 1=>NotStarted (default); 2=> InProgress; 3=>Complete
}
One simple way can be that you make a different class for child notes and notify your parent class each time when its property is changed:
Parent
public class Node
{
public string Name { get; set; }
public List<Node> Children { get; set; } = new List<Node>();
private int _nodeStatus;
// 1=>NotStarted (default); 2=> InProgress; 3=>Complete
public virtual int NodeStatus
{
get => _nodeStatus;
set
{
_nodeStatus = value;
// If started, then change all children property to 'In progress'
if(value == 2)
Children.ForEach(child => child.NodeStatus = 2);
}
}
private int CountCompleted { get; set; }
public void NotifyChildChanged(int childStatus)
{
if (childStatus == 3)
{
CountCompleted++;
if(CountCompleted == Children.Count)
// Do your stuff
}
else
{
CountCompleted--;
}
}
}
Child
public class ChildNode : Node
{
private int _nodeStatus;
public override int NodeStatus
{
get => _nodeStatus;
set
{
_nodeStatus = value;
NotifyChildChanged(value);
}
}
}
Basically, what you will have is a separate implementation of NodeStatus for Parent and Child classes and inside of their implementation you just put other needed methods like changing childs' values or notifying parent about child's complete. In the parent's case, however, you should be careful, because every time you change the parent it will change all children, so you might want to have also some kind of private bool which will be checking whether the progress has already been started or not.
P.S for simplicity, I used just methods, however, you might want to implement it through delegates and events.
I have method that walks through a class and checks if 2 objects has the same values.
private bool LoopThroughObjects<T>(T ob1, T ob2)
{
Type type = ob1.GetType();
System.Reflection.PropertyInfo[] props = type.GetProperties();
foreach (var prop in props)
{
object ent1value = prop.GetValue(ob1, new object[] { });
object ent2value = prop.GetValue(ob2, new object[] { });
//If object is in the same namespace it's a nested element
if(IsSameNameSpace(type.Namespace, prop.PropertyType.Namespace))
{
_depth++;
ValidateEntity_AttributesNotSame(ent1value, ent2value);
}
else
ComparerOutput.Add(_conjunction + prop.Name, ent1value.Equals(ent2value));
if (BreakOnUnequally)
if (!ent1value.Equals(ent2value))
return false;
}
return true;
}
A example of an object that I can send:
public class RefelctionTestEntity
{
public int Id { get; set; }
public String Firstname { get; set; }
public String Lastname { get; set; }
public int Age { get; set; }
public RefelctionTestEntity Child { get; set;}
public Vehicle.Bikes Bike { get; set; }
}
I walk recursively through the object so I will also check the Child en the Bike. My question is what's the best methode to check these inner objects?
What I do at this moment is check the namespace of the object against the parent namespace of the inner object:
private bool IsSameNameSpace(String baseNamespace, String propertyNamespace)
{
if (String.IsNullOrEmpty(baseNamespace) || String.IsNullOrEmpty(propertyNamespace))
return true;
if (String.IsNullOrEmpty(baseNamespace) || String.IsNullOrEmpty(propertyNamespace))
return false;
String[] part = propertyNamespace.Split('.');
return part[0].Equals(baseNamespace);
}
//If object is in the same namespace it's a nested element
Using such a rule could quickly become a problem in future.
It would be much more convenient if you flag the recursive item property with an interface and check whether the current property implements that interface. If so just go one level deeper.
Otherwise check if the values of the property you are currently looking at match for both objects.
var interf = Text.GetType().GetInterface("MyInterface",false);
Another approach would be to use an attribute over the item to flag it.
The check for attribute would look like this :
var att = Text.GetType().GetCustomAttributes(typeof(RecursiveTypeAttribute),false);
I wouldn't check if the current property is a reference type since you could easily introduce a reference type property in the future.
I have come upon an issue I can't seem to figure out. I'm sure there's a simple explanation to this, but I don't understand why I get a System.Reflection.TargetException: 'Object does not match target type' when I try to get a property from (in this case) the employee object.
employee.GetType().GetProperty(property.Name)
Searching for the error returns many results describing problems with calling the Set/GetValue methods, but I haven't found a solution to this one.
I've set a breakpoint where the exception is thrown and it shows that property.Name is indeed a value - and a real property of the object. I've also tried manually specifying a property I know exists. Still the same.
Any suggestions?
EDIT: Tried the following instead:
Type type = typeof (Employee); //Throws the TargetException
PropertyInfo theProperty = type.GetProperty(property.Name);
And now the same exception is thrown at the first line above instead.
EDIT: Added code and more details about the application I'm building.
Class definition for Employee (to simplify mapping to the JSON data this class "represents", the class/fields are in Norwegian - which is the format/language the data comes in, sorry :-).)
"Ansatt" = Employee. "Ansattnummer" = EmployeeNo.
[JsonObject]
public class Ansatt
{
public int Ansattnummer { get; set; }
public string Fornavn { get; set; }
public string Etternavn { get; set; }
public int Pin { get; set; }
public string Adresse { get; set; }
public int Postnummer { get; set; }
public string Poststed { get; set; }
public int TlfPrivat { get; set; }
public int MobilTlf { get; set; }
public string EpostAdresse { get; set; }
public DateTime Fodt { get; set; }
}
My application retrieves a given dataset from a web service - it could be employees, projects or a few other possible datasets. What data to fetch is determined at runtime - by the user. The user can also specify via URL-query which portions, e.g. columns, of the dataset he/she wants. The program then creates a csv-file with the selected data.
Here's the code I use for this:
if (records != null && records.Count != 0) //records contains the chosen dataset - in this case Employees (Ansatt).
{
if (records.GetType() == typeof (List<Ansatt>))
{
foreach (var model in records as List<Ansatt>)
{
var temp = new Ansatt();
foreach (var property in model.GetType().GetProperties())
{
var currentProperty = model.GetType().GetProperty(property.Name);
if (currentProperty != null)
{
Type type = typeof (Ansatt); //Throws System.Reflection.TargetException: 'Object does not match target type'
PropertyInfo tempProperty = type.GetProperty(property.Name);
tempProperty.SetValue(temp, currentProperty.GetValue(property.Name));
}
}
csv.WriteRecord(temp);
}
}
}
You need to specify the name of the property
PropertyInfo value = employee.GetType().GetProperty("Name");
As MSDN goes, you should use it this way:
class MyClass {
private int myProperty;
// Declare MyProperty.
public int MyProperty {
get {
return myProperty;
}
set {
myProperty = value;
}
}
}
public class MyTypeClass {
public static void Main(string[] args) {
try {
// Get the Type object corresponding to MyClass.
Type myType = typeof(MyClass);
// Get the PropertyInfo object by passing the property name.
PropertyInfo myPropInfo = myType.GetProperty("MyProperty");
// Display the property name.
Console.WriteLine("The {0} property exists in MyClass.", myPropInfo.Name);
// Instantiate MyClass
var myObject = new MyClass()
{
MyProperty = 5
};
// Get value using reflection
Console.WriteLine("My property value for my object is {0}.", myPropInfo.GetValue(myObject));
} catch (NullReferenceException e) {
Console.WriteLine("The property does not exist in MyClass." + e.Message);
}
}
}
For your code, when you want to get the property value of an object instance, you should pass object as reference to PropertyInfo.GetValue(object) function.
Instead of this:
tempProperty.SetValue(temp, currentProperty.GetValue(property.Name));
Do this:
tempProperty.SetValue(temp, currentProperty.GetValue(model));
For you to get the property of object through reflection, make it sure that the property name is public with getter and setter else it will return null.
Ex.
public class Employee
{
public string YouProperty { get; set; }
}
var employee = new Employee();
var result = employee.GetType().GetProperty("YouProperty");
// The result is property info
Kindly read some information here.
I have this class:
public class ExtraDisplayItems
{
public int ItemId { get; set; }
public string ItemCode { get; set; }
public string ItemDescription { get; set; }
public double? ItemSellingPrice { get; set; }
}
I then add data to the class with the method below:
using (TruckServiceClient TSC = new TruckServiceClient())
{
var item = cmbAddExtras.SelectedItem as ExtraDisplayItems;
if (item != null)
{
var displayItem = new List<ExtraDisplayItems>
{
new ExtraDisplayItems
{
ItemId = item.ItemId,
ItemCode = item.ItemCode,
ItemDescription = item.ItemDescription,
ItemSellingPrice = item.ItemSellingPrice
}
};
dgAddExtras.Items.Add(item);
}
}
Now what I want to do is create a read-only property where I would get the total Sum of the ItemSellingPrice, but in this property I cannot reach the Sum when trying to calculate the double?
This is how I wan't the coding to work:
public double? SubTotalExtras
{
get { return ExtraDisplayItems.Sum(x => x.ItemSellingPrice); }
}
But... it's giving me the error:
ExtraDisplayItems does not contain a definition for 'Sum'
How would I go about fixing this?
EDIT
I have changed the class to:
public class ExtraDisplayItems
{
private List<ExtraDisplayItems> displayItems;
public int ItemId { get; set; }
...
}
And...
if (item != null)
{
this.displayItems = new List<ExtraDisplayItems> //Error
{
new ExtraDisplayItems
{
...
}
};
dgAddExtras.Items.Add(item);
}
But it now throws the error: does not contain definition for 'displayItems'
It seems dat ExtraDisplayItems is an instance of the ExtraDisplayItems class, which doesn't implement IEnumerable<T> (that is: 'it is a collection of something'). That means that it indeed doesn't have a Sum method, nor does the extension method apply.
My best guess at the moment is that you should save the displayItem (which is a List<ExtraDisplayItems>, so it implements IEnumerable<ExtraDisplayItems>) somewhere in your view model and call Sum on that.
Also, use naming conventions: you are making plurals singular and the other way around... Very confusing...
You are probably missing Linq in your using definitions.
using System.Linq;
EDIT:
I was assuming ExtraDisplayItems was a collection, then it is common to have the error 'x does not contain a definition for 'Sum'' even if you see it in code samples.
In order to do the sum various objects you actually need a collection of them not a single object.
I have an abstract class that looks like so:
public abstract class PageObjectsBase
{
public abstract string FriendlyName { get; }
public abstract string PageObjectKeyPrefix { get; }
public abstract string CollectionProperty { get; }
}
And a class that derives from PageObjectsBase:
public class PageRatingList : PageObjectsBase
{
public IList<PageRating> PageRatings { get; set; }
public PageRatingList()
{
this.PageRatings = new List<PageRating>();
}
public override string CollectionProperty
{
get
{
var collectionProperty = typeof(PageRatingList).GetProperties().FirstOrDefault(p => p.Name == "PageRatings");
return (collectionProperty != null) ? collectionProperty.Name : string.Empty;
}
}
public override string FriendlyName
{
get
{
return "Page feedback/rating";
}
}
public override string PageObjectKeyPrefix
{
get
{
return "pagerating-";
}
}
}
And a PageRating class which PageRatingList.PageRatings is holding a collection of:
public class PageRating : PageObjectBase
{
public int Score { get; set; }
public string Comment { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
The PageRatingList is being stored in a database (EPiServer's Dynamic Data Store, more specifically using the Page Object Manager). I need to create some reporting functionality and am essentially loading all reports that derive from PageObjectBase. When it comes to returning the data, the code will never know at compile time what type of data it is to load, so I am using Reflection. In my reporting class I have:
//this gives me the right type
var type = Type.GetType("MyNameSpace.PageRatingList", true);
var startPageData = this._contentRepository.Get<PageData>(startPage);
PageObjectManager pageObjectManager = new PageObjectManager(startPageData);
//this loads the instances from the DB
var props = pageObjectManager.LoadAllMetaObjects()
.FirstOrDefault(o => o.StoreName == "Sigma.CitizensAdvice.Web.Business.CustomEntity.PageRatingList");
//this gives me 4 PropertyInfo objects (IList: PageRatings, string : CollectionProperty, string :FriendlyName, string : PageObjectKeyPrefix)
var properties = props.Value.GetType().GetProperties();
I can then iterate through the PropertyInfo objects using:
foreach (var property in properties)
{
//extract property value here
}
The issue I am having is that I cannot figure out how to get the value of each of the propertyinfo objects. In addition, one of those properties is type List and again we wont know the type of T until runtime. So I also need some logic that checks if one of the PropertyInfo objects is of type List and then provides access to each of the properties in the List - the List being of type PageRating.
Can anyone help here? I've not really used reflection in the past so I am winging my way through it, rightly or wrongly!
Many thanks
Al
I may be missunderstanding the problem, but i think you may use something like this:
var props = new PageRatingList(); /*actual instanse of the object, in your case, i think "props.Value" */
var properties = typeof(PageRatingList).GetProperties();
foreach (var property in properties)
{
if (property.PropertyType == typeof(IList<PageRating>))
{
IList<PageRating> list = (IList<PageRating>)property.GetValue(props);
/* do */
}
else
{
object val = property.GetValue(props);
}
}
Hope this helps to find your solution.