Get value from a dictionary created from a PropertyInfo.GetValue - c#

How to get this to work?
GSD a class that is used to store cache images of SQL tables. GSD has several public static properties representing different "CacheTables", which are Dictionary=long,rowtypeclass= objects, each with a different rowtype class. The rowtype class objects model SQL table rows.
public class GSDataObject
{
private Dictionary<long, GRPListRow> prvGRPList;
private Dictionary<long, TestTableRow> prvTestTable;
//=======================================
public Dictionary<long, GRPListRow> GRPList
{
get { return prvGRPList;}
set { prvGRPList = value; }
}
//=====================================
public Dictionary<long, TestTableRow> TestTable
{
get { return prvTestTable; }
set { prvTestTable = value; }
}
public class TestTableRow{
public int ID { get; set; }
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
public string Field4 { get; set; }
public string Field5 { get; set; }
public string Field6 { get; set; }
public string Field7 { get; set; }
public string Field8 { get; set; }
}
GSD and its different CacheTable properties work fine when declared hard-coded; I want to access them with reflection.
Specifically, I want to get a particular Row from a particular CacheTable in an instance of GSD, update that row, and then put it back. The instructions below describe the "get the row" phase.
The first three instructions work, and the resulting wrkCacheTableObject is of the correct type Dictionary=long,wrkRowtype=. However, wrkCacheTableObject is not indexed, so I can't retrieve rows from it.
wrkGSD is an instantiation of a class GSD. wrkCacheTableName is a string name of the particular CacheTable property. wrkRowType is the string class name of the row type.
wrkRow = Activator.CreateInstance(wrkRowType);
PropertyInfo wrkTablePropInfo = wrkGSDOType.GetProperty(wrkCacheTableName);
object wrkCacheTableObject = wrkTablePropInfo.GetValue(wrkGSD, null); // <== gives correct CacheTable instance
wrkTableDictObject = (Dictionary<long, object>)wrkCacheTableObject; //<=== fails here
wrkRow = wrkTableDictObject[wrkRowID];
// update wrkRow fields using reflection //<== this works if I retrieve wrkRow via hard code
// put it back into wrkTableDictObject
// put wrkTableDictObject back into wrkGSD
I'm not fixed on this particular set of instructions. And maybe if I can get the first phase above to work, it will show me how to do the other phases.

Found the answer via Experts Exchange:
dynamic wrkCacheTableObject = wrkTablePropInfo.GetValue(wrkGSD, null);
//--- get the row using dynamic
dynamic wrkRow = wrkCacheTableObject[(long)varAJR.rowID];
//--- put the row back
wrkCacheTableObject[(long)varAJR.rowID]= wrkRow;

Related

Assigning data to attributes and static attributes directly in c#

I have a method as follows which gets data and stores them to specific variables. I also have two static variables that preserves their value if a condition is met. My question is how can I store this data in attributes in a specific class ?
Like for example, I have a class called UserDetails with attributes :
UserDetails class
public class UserDetails {
public static string RateCountry { get; set; }
public static string RateWeek { get; set; }
public int Start { get; set; }
public int Length { get; set; }
public string Name { get; set; }
public string Address { get; set; }
}
Second Class
For now, its working like this. But I want to enhance it by making use of objects.
public static string RateCountry { get; private set; }
public static string RateWeek { get; private set; }
public ActionResult ShowList()
{
int start = Convert.ToInt32(Request["start"]);
int length = Convert.ToInt32(Request["length"]);
string name = Request["search[value]"];
string address = Request[("columns[3][search][value]")];
string rateType = Request[("columns[7][search][value]")];
if (string.IsNullOrEmpty(rateType)) // if null, reset the static variables to null
{
RateCountry = "";
RateWeek = "";
}
else
{
if (CheckDate(rateType)) // if contains date, assign to RateWeek
{
RateWeek = rateType;
}
else
{
RateCountry = rateType; // else if contains a string word, assing to ratecountry
}
}
var items = AssignDetails(start, length, name, address, RateWeek, RateCountry);
return items;
}
Then instead of passing several parameters like start, length, name etc. in the method AssignDetails, I can pass an object of the UserDetails class directly taking into consideration the static variables.
Can someone please help ?
Note: In C#, they are called properties not attributes. Attributes are a totally different thing.
What you want to do is straight forward:
Firstly, you need to change your method so it accepts your class UserDetails as an argument:
public void AssignDetails(UserDetails userDetails)
{
// Use userDetails here to do whatever you want
}
Secondly, when you call the above method, you need to pass the argument to it. You can create an instance of UserDetails and pass it to the AssignDetails method:
var userDetails = new UserDetails
{
Start = start,
Length = length,
Name = name
Address = address
}
I am not sure why RateWeek, and RateCountry properties are static in your class, but to set those you can do them as below (Please note it is using the class and not the instance of the class):
UserDetails.RateWeek = RateWeek;
You could make use of the instance's properties as an indirection to the class' static properties, although all this thing is really ugly in terms of design.
public class UserDetails
{
public static string PersistedRateCountry { get; set; }
public static string PersistedRateWeek { get; set; }
public static string RateCountry
{
get { return string.IsNullOrEmpty(rateType) ? "" : PersistedRateCountry; }
set { PersistedRateCountry = value; }
}
public static string RateWeek
{
get { return string.IsNullOrEmpty(rateType) ? "" : PersistedRateWeek; }
set { PersistedRateWeek= value; }
}
public static string RateWeek { get; set; }
public int Start { get; set; }
public int Length { get; set; }
public string Name { get; set; }
public string Address { get; set; }
}
I strongly suggest you to move these static properties out to another class, which would be responsible for persisting them.
E.g. try to separate your Data Object (which just holds data) from your Business Object (which contains business logic, and is constructed by receiving a Data Object as parameter). Put all that crazy persistence logic in the Business Object, and use the Business Object everywhere in your code (instead of using the Data Object).
Keep your classes short and clean. If you are coding a lot in the same class, it's probably because you got a bad object-oriented design.

C# How to initialize an object containing a list<T> with standard values

This question is related to this question. I managed to get one step further, but I am now unable to initialize my whole object with default values in order to prevent it from being null at list level. The goal of this is to hand down the "null" values to my SQL query. Ultimately what I want is one record in my DB that will express: This row has been recorded, but the related values were "null".
I have tried Brian's fiddle and it does not seem to work for me to initialize the whole model with standard values.
Expectation: Upon object initialisation the "null" values should be used and then overwritten in case there is a value coming through JSON deserialisation.
Here is what I have tried. None of this will have the desired effect. I receive this error:
Application_Error: System.ArgumentNullException: Value cannot be null.
Every time I try to access one of the lists in the data model.
namespace Project.MyJob
{
public class JsonModel
{
public JsonModel()
{
Type_X type_x = new Type_X(); // This works fine.
List<Actions> action = new List<Actions>(); // This is never visible
/*in my object either before I initialise JObject or after. So whatever
gets initialised here never makes it to my object. Only Type_X appears
to be working as expected. */
action.Add(new Actions {number = "null", time = "null", station =
"null", unitState = "null"}) // This also does not prevent my
//JsonModel object from being null.
}
public string objectNumber { get; set; }
public string objectFamily { get; set; }
public string objectOrder { get; set; }
public string location { get; set; }
public string place { get; set; }
public string inventionTime { get; set; }
public string lastUpdate { get; set; }
public string condition { get; set; }
public Type_X Type_X { get; set; }
public List<Actions> actions { get; set; }
}
public class Actions
{
public Actions()
{
// None of this seems to play a role at inititialisation.
count = "null";
datetime = "null";
place = "null";
status = "null";
}
// public string count { get; set; } = "null"; should be the same as above
// but also does not do anything.
public string count { get; set; }
public string datetime { get; set; }
public string place { get; set; }
public string status { get; set; }
}
public class Type_X
{
public Type_X
{
partA = "null"; // This works.
}
public string partA { get; set; }
public string PartB { get; set; }
public string partC { get; set; }
public string partD { get; set; }
public string partE { get; set; }
}
}
This is how I now initialize the object based on Brian's answer.
JObject = JsonConvert.DeserializeObject< JsonModel >(json.ToString(), new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore});
When I try to iterate over Actions' content, it (logically) gives me above mentioned null error.
for (int i = 0, len = JObject.actions.Count(); i < len; i++)
My current understanding of constructor initialisations:
If I define values such as count = "null"; they should appear in any new object that is created.
If default values are present I would then also expect that a list that has items with default values (such as count for ex.) would be of Count() 1 and not null. How is that even possible?
This will get you out of your bind:
private List<Actions> _actions = new List<Actions>();
public List<Actions> actions { get => _actions; set => _actions = value ?? _actions; }
This causes trying to set actions to null to set it to the previous value, and it is initially not null so it can never be null.
I'm not absolutely sure I'm reading your question right, so here's the same fragment for partA:
private string _partA = "null";
public string partA { get => _partA; set => _partA = value ?? _partA; }
I have found that in some cases, initializing generic lists with their default constructor on your model increases ease of use. Otherwise you will always want to validate they are not null before applying any logic(even something as simple as checking list length). Especially if the entity is being hydrated outside of user code, i.e. database, webapi, etc...
One option is to break up your initialization into two parts. Part 1 being the basic initialization via default constructor, and part 2 being the rest of your hydration logic:
JObject = new List < YourModel >();
... < deserialization code here >
Alternatively you could do this in your deserialization code, but it would add a bit of complexity. Following this approach will allow you to clean up your code in other areas since each access will not need to be immediately proceeded by a null check.

C# WPF Bind a specific object of a list to a GridViewColumn

i'm working on this since a while but didn't solved my problem.
The Case:
I have list A which contains objects of Info.
Info has the properties id, name and list B which contains objects of Details.
Details has the properties id, Name and a bool.
Is it possible to bind list A to a ListView and show the property of an object from list B where the bool is true?
edit:
List B contains more than one object but only one of the objects has a true bool, the others have false. I want to show the Name of the object with the true bool in the GridViewColumn with Binding but didn't find a way till now
public class Info
{
public int Id { get; set; }
public string Name { get; set; }
List<Detail> Details { get; set; }
public string GoodDetails
{
get { return String.Join(",", Details.Where(x => x.Good == true).Select(y => y.Name)); }
}
}
public class Detail
{
public int Id { get; set; }
public string Name { get; set; }
public bool Good { get; set; }
}
So taking from your list of Details with the bool (which I called Good) set to true, I make a separate property called GoodDetails which pulls all of the names into a comma delimited string. So you just bind to GoodDetails

Azure Table Storage Not saving Property

I have an abstract class that inherits from Table Entity.
public abstract class AzureEntityBase : TableEntity
{
public AzureEntityBase()
{
}
public virtual string TableName
{
get
{
return string.Empty;
}
}
private string ObjectHash { get; set; }
public bool IsBackedUp { get; set; }
}
I then have a class that implements this abstract class
public class DepartmentTotalEntity : AzureEntityBase
{
public override string TableName
{
get
{
return "DepartmentTotals";
}
}
public Int64 SessionDateTimeInteger { get; set; }
public string StoreID { get { return PartitionKey; } set { PartitionKey = value; } }
public string DetailKey { get; set; }
public string RangeString { get; set; }
public string DateStart { get; set; }
public string DateEnd { get; set; }
public Int64 DateStartInt { get; set; }
public Int64 DateEndInt { get; set; }
public string Dept_ID { get; set; }
public string DepartmentDescription { get; set; }
public decimal Quantity { get; set; }
public decimal TotalPrice { get; set; }
}
I am submitting a revised entity to Azure table storage with the IsBackedUp value set to false.
I then have a service that runs on an Azure Compute instance that copies the row from one table storage account to another. The other Azure table storage account is at a different Azure datacenter. After all the rows are copied, I want to limit what I grab when I copy the next round and the IsBackedUp field is supposed to do this.
I run a function that loops the rows already inserted, checks to see if they exist at the destination, if they do exist, then update the source table row to reflect that it was backed up and write that to azure via the following code.
foreach (DepartmentTotalEntity row in CopiedRows)
{
DepartmentTotalEntity find = dst.BrowseSingle(row.PartitionKey, row.RowKey);
if (find != null)
{
row.IsBackedUp = true;
int tmp = src.InsertOrReplace(row);
}
}
The return integer from the InsertOrReplace is the HttpStatusCode of the tableoperation and it always reads 204. This is expected for a successful write the ATS.
For completeness here is the InsertOrReplaceRow function.
public int InsertOrReplace(DepartmentTotalEntity input)
{
if (input.PartitionKey.IsNull())
{
throw new ArgumentNullException("PartitionKey");
}
if (input.RowKey.IsNull())
{
throw new ArgumentNullException("RowKey");
}
TableOperation replaceOperation = TableOperation.InsertOrReplace(input);
TableResult result = table.Execute(replaceOperation);
return result.HttpStatusCode;
}
The main problem is that the IsBackedUp field is not being updated when the InsertOrReplace command is being called in the third block of code.
Banging me head against a wall here trying to figure out why ATS will not accept my revision.
I can successfully change the value of IsBackedUp using Azure Table Storage Explorer. I have confirmed that the datatype of the column is Boolean.
Any help would be greatly appreciated. Let me know if I have posted enough of the code to be of assistance. The only class that is not posted is the rest of the class that surrounds the last code block. It is over 2000 lines so I omitted it for brevity. That class has the CloudTable, CloudTableClient and CloudStorageAccount variables.

Get the values of a particular object from a C# List of objects

I'm working in a WPF window in which I have a class which is fetching data from the database using dbset.
Below is the view model class of data.
public class CriteriaSheetVM
{
public string ReviewNumber { get; set; }
public string EmployeeFirstName { get; set; }
public string EmployeeLastName { get; set; }
}
and i'm creating a list of above class objects:
List<CriteriaSheetVM> criteriaSheet;
My query is to get all the values stored in the EmployeeLastName from the above List and to compare each value with the value in the TextBox txtEmpLastName and return TRUE when found else FALSE.
UPDATE:
I have used below code for it.
criteriaSheet.ForEach(a =>
{
if (a.EmployeeLastName == txtEmpLastName.Text)
{
bool flag = 1;
}
});
and it was not working
If you want multiple result:
var results = criteriaSheet.Where(cs=>cs.EmployeeLastName ==txtEmpLastName.Text);
If you want to one result:
var result = criteriaSheet.FirstOrDefault(cs=>cs.EmployeeLastName ==txtEmpLastName.Text);

Categories

Resources