I'm currently working on an app using Asp.Net MVC and C#. One of the requirement is to check what process the item is and then to only show the appropriate div. So I've decided to create a Table in the Db which consist of:
Id ProcessDescription DivOneVisible DivTwoVisible
1 Approved True False
2 Analysis True True
...
NOTE - The Id's and ProcessDescription will never change
Currently the table only holds 10 rows of data but the idea is, in future more rows/columns can be added.
I then go ahead and create the appropriate methods, one for each Div as follows
public bool ShowDivOne(int id)
{
var data = uow.GetRepository<ItemProcess>().GetById(id);
bool showDivOne = data.DivOneVisible.HasValue ? data.DivOneVisible.Value : false;
if (showDivOne)
return true;
else
return false;
}
I use the same code as above for ShowdivTwo() method, but match the different column. Then in the view I do
#if(ShowDivOne){//div one code here}
#if(ShowDivTwo){//div two code here}
This works but I was wondering if there is a more generic way where I can write one method which will cover each scenarios even if new columns or rows are added.
The main thing you still need to have a mapping between Database and ViewModel somewhere. At the moment it is hard coded in your methods.
You can make it absolutely generic if you start use reflection and have a mapping array with properties name. But I would nt recommend doing it as it over complication and hard to maintain and change.
(If you want I can go into details of implementation).
For you example I would suggest to have a viewmodel per item, that contains properties of divs to display.
public class ProcessViewModel
{
public int Id {get;set;}
public bool ShowDivOne {get;set;}
public bool ShowDivTwo {get;set;}
ProcessViewModel(){}
ProcessViewModel(ItemProcess data){
Id = data.Id;
ShowDivOne = data.DivOneVisible.HasValue ? data.DivOneVisible.Value : false;
ShowDivTwo = data.DivTwoVisible.HasValue ? data.DivTwoVisible.Value : false;
}
}
You still query for each item individually or query them altogether and pass data to viewmodel to construct it.
And a simple foreach on a view to traverse through the list of viewmodels.
Extending it to contain more properties would be very easy and strait forward, with minimum code to maintain.
Related
Introduction
I found a very weird situation, so essentially I've a collection property called Matches and an object property called Match.
The Matches collections contains a list of item of Match, like this:
private ObservableCollection<Match> _matches = new ObservableCollection<Match>();
public ObservableCollection<Match> Matches
{
get { return _matches; }
}
this collection is valorized when the application start, infact, the software take some data from an Internet site and then, with a scraper fill the collection with the correspond object model Match.
Where the bug start
The Matches collection is binded to a DataGrid. When the user click on an element (Match), available on the DataGrid, the code fire the event SelectionChanged, inside this event I create a copy of the Match clicked, so I can use this object inside all my application:
var match = controller.Matches.FirstOrDefault(c => c.MatchLink == ((Match)Matches.SelectedItem).MatchLink);
as you can see with the use of Linq, I check if the Match clicked by the user have the same link of a Match contained in the Matches collection, infact, each Match in the collection have a unique link like a GUID for example.
The bug
The Match object look like this:
private Match _match;
public Match Match
{
get { return _match; }
set
{
_match = value;
OnPropertyChanged();
}
}
and as I said it contains the Match clicked by the user. This object allow me to get the data from Internet only for this Match, from all methods inside my app. This working pretty well. Until now.
My application allow the user to apply some filters, essentially the user press a button and then the Match saved is updated with the property filled by the user, for example:
Match.League.Rounds = availableRounds;
this code cause the bug, but I'll try to explain the bug better later, I need to explain a bit what happen here.
Essentially the current Match saved in the application should update only the own property League.Rounds, this property is a list of Rounds available for this Match, the structure is very simple:
public class Round
{
public int Id { get; set; }
public string Name { get; set; }
}
the update working good but, the line Match.League.Rounds = availableRounds; update also all the property League.Rounds available in the objects collection Matches.
I don't understand why happen this, I've not created a reference of the object clicked:
var match = controller.Matches.FirstOrDefault(c => c.MatchLink == ((Match)Matches.SelectedItem).MatchLink);
Practice example of what's happening
before filters applied
Matches Collection
Match.Leagues.Rounds[0] contains Id 10 and Name foo
after filters applied
Matches Collection
Match.Leagues.Rounds[0] contains Id 11 and Name foofoo
but it should not be modified, only the Match should be modified.
but a new object. Someone could explain how to fix this? Best regards.
I've not created a reference of the object clicked
Yes, you have. This does not create a new Match object:
var match = controller.Matches.FirstOrDefault(c => c.MatchLink == ((Match)Matches.SelectedItem).MatchLink);
It gets a reference to the already existing Match object in the Matches collection.
If you want to create a new object, you should use the new operator:
var existing = controller.Matches.FirstOrDefault(c => c.MatchLink == ((Match)Matches.SelectedItem).MatchLink);
Match match = new Match();
//set all properties of the new object...
match.Prop1 = existing.Prop1;
Also note that you need to create new Round objects as well. You should consider implementing the IClonable interface.
The FirstOrDefault() method doesn't clone the object for you.
I followed the great advice here (Handling calculated properties with breezejs and web api) to allow Breeze to access my calculated properties which I have set up in a partial class on the server side:
public partial class EventPerson
{
[NotMapped]
public Decimal TotalAmountPaid
{
get
{
return this.EventPersonPayments.Sum(p => p.AmtPaid);
}
}
}
But for each EventPerson I retrieve, this value shows up as 0 unless I use .expand("EventPersonPayments") clientside or .Include("EventPersonPayments") serverside.
I don't want all the data in EventPersonPayments to be serialized and sent to the client; all I want is the summed value. Is this possible?
EDIT: If my calculated property is derived from other properties already in the entity, it works fine. For example:
public partial class EventPerson
{
[NotMapped]
public String DisplayName
{
get
{
return this.FirstName + " " + this.LastName;
}
}
}
returns the DisplayName in the JSON payload. The former type of calculated property always returns 0 or null unless I specifically load all the extra information.
I considered converting these into User Defined Functions in SQL Server, but I shouldn't have to throw out my C# code just to make it work the way it should.
One approach is to use a projection that incorporates both the entities being queried and some calculated properties as well. i.e. your server query might look like this:
[HttpGet]
public IQueryable<Object> CustomersAndFreightTotals(companyName) {
var stuff = ContextProvider.Context.Customers
.Where(c => c.CompanyName.StartsWith(companyName))
.Select(c => new { Customer = c, FreightTotal = c.Orders.Sum(o => o.Freight)) });
return stuff;
}
This query will load all of your customers that start with a specified company name but will also give you the "total freight" for all of the orders on each customer.
You would call this with code something like this:
var query = EntityQuery.from("CustomersAndFreightTotals")
.withParameters({ companyName: "C" });
myEntityManager.executeQuery(query).then(function(data) {
var results = data.results;
results.forEach(function (r) {
// note that each customer WILL also be added to the local entityManager
// because it is an entity, whereas the freightTotal is only available here.
var customer = r.Customer;
var freightTotal = r.FreightTotal;
// and if you wanted to hack the customer entity
// you could do this.
customer.freightTotal = freightTotal;
});
}
I came across this problem also, and there are a couple of other questions/answers that seem to point to what's going on:
My unmapped properties in breeze does not seems to work whith a projection
UnMapped property on the Angular/Breeze SPA template
From my understanding, to put it shortly, [NotMapped] prevents Breeze/Entity Framework from correctly wiring up to the field. Yet Json.NET will serialize the field and send it to Breeze, which will populate the field if you've manually set it up via the class's constructor, and the data has been retrieved by using expand for the other property which Entity Framework recognizes. This seems to be almost an accident you can get [NotMapped] fields to work on the client in this given case; the Breeze+Entity Framework does not seem to be designed for this case.
There is a suggestion at Breeze's User Voice that you could vote and comment on. I'm not sure that Breeze could solve this problem themselves without some work from the Entity Framework team, but at least it could put the issue on their radar.
I am looking for help on an issue with NHibernate which has been bugging me for a while now. Long story short:
I’m looking for a way to, in the first level cache, “reset” a property on an entity each time I do an update or an insert.
What I want to achieve is that the property in question will always be considered to be dirty by NHibernate when using dynamic update or insert.
The backstory for this is that I know that, if the transaction was successful, the column that I want to “reset” will be set to Null in the database by a trigger. On the flip side, the first level cache does not know this, and thus NHibernate will think that the property was not updated when I set it to the same value as I did on the previous update/insert. The catch is that my trigger is dependent on this value being set. The resulting mess is that if I want to use dynamic update or insert I’m only able to update/insert an entity once without “refreshing” it afterwards (which I really don’t want to do).
Tips or help would be much appreciated, because I’ve really hit a wall here
NHibernate provides many places for extension. Among them is the Session IInterceptor. There is documentation with many details:
http://nhibernate.info/doc/nh/en/index.html#objectstate-interceptors
In this case, we can create our custom one, which will be observing our entity (for example Client) and a property which must be updated every time (for example Code). So our implementation could look like this:
public class MyInterceptor : EmptyInterceptor
{
public override int[] FindDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, NHibernate.Type.IType[] types)
{
var result = new List<int>();
// we do not care about other entities here
if(!(entity is Client))
{
return null;
}
var length = propertyNames.Length;
// iterate all properties
for(var i = 0; i < length; i++)
{
var areEqual = currentState[i].Equals(previousState[i]);
var isResettingProperty = propertyNames[i] == "Code";
if (!areEqual || isResettingProperty)
{
result.Add(i); // the index of "Code" property will be added always
}
}
return result.ToArray();
}
}
NOTE: This is just an example! Apply your own logic for checking the dirty properties.
And we have to wrap Session this way:
var interceptor = new MyInterceptor()
_configuration.SetInterceptor(interceptor);
And this is it. While Client is marked as dynamic-update, the property Code will always be set as dirty
<class name="Client" dynamic-update="true" ...
I am trying to setup a WPF datagrid. The standard datagrid is setup to accept a list of objects which are displayed on different rows, with a column for each property. I actually need to do the inverse; a row for each property, and a column for each object in the list. Therefore I started with the solution proposed by blindmeis here in order to handle a dynamic number of columns and it works well so far.
I have a class DataGridVM to which I can pass a list of objects. Each of the objects has its own View Model which derives from a class ParentalBaseVM. Each property of that object has its own View Model which derives from a class ElementVM.
Each ParentalBaseVM can return list of ElementVM for each of its object’s properties through overriding the virtual method PropertyLists
E.g. within an example of a class dervived from ParentalBaseVM I have:
public override Dictionary<string, List<ElementVM>> PropertyLists
{
get
{
Dictionary<string, List<ElementVM>> iPropertyLists = new Dictionary<string, List<ElementVM>>();
List<ElementVM> BasicProperties = new List<ElementVM>();
BasicProperties.Add(iNBViewModel);
BasicProperties.Add(iIDViewModel);
iPropertyLists.Add("Basic", BasicProperties);
List<ElementVM> AdvancedProperties = new List<ElementVM>();
AdvancedProperties.Add(iNBViewModel);
AdvancedProperties.Add(iIDViewModel);
AdvancedProperties.Add(iXSAreaViewModel);
iPropertyLists.Add("Advanced", AdvancedProperties);
return iPropertyLists;
}
set
{
}
}
As you can see, I can return a different set of properties by passing either “Basic” or “Advanced” as a string.
The DataGridVM code is below. I pass to this the list of objects (columnList) and the string which represents the (“Basic” or “Advanced” in the example above)
class DataGridVM
{
private List<List<ElementVM>> iDataList;
public DataGridVM(List<ParentalBaseVM> columnList, string rowListKey)
{
iDataList = new List<List<ElementVM>>();
for (int i = 0; i < columnList[0].PropertyLists[rowListKey].Count; i++)
{
List<ElementVM> newRowList = new List<ElementVM>();
for (int j = 0; j < columnList.Count; j++)
{
newRowList.Add(columnList[j].PropertyLists[rowListKey][i]);
}
iDataList.Add(newRowList);
}
}
public List<List<ElementVM>> DataList
{
get
{
return iDataList;
}
set
{
}
}
}
Finally, the datagrid is populated using:
testControlDataGrid.testDataGrid.ItemsSource = testDataGridVM.DataList;
And then the columns are generated dynamically (the code within CreateDataTemplate sets up the bindings)
for (int i = 0; i < testDataGridVM.DataList[0].Count; i++)
{
testControlDataGrid.testDataGrid.Columns.Add(new DataGridTemplateColumn()
{
Header = "Col" + i,
CellTemplate = CreateDataTemplate(TheTextBlock.GetType(),i)
});
}
This all works fine, but it feels very messy. Passing string values like “Basic” and accessing dictionaries feels wrong. Perhaps there is an elegant solution where I have classes deriving from DataGridVM such as DataGridVMBasicProperties which accesses the “Basic” properties of the object, but I’m not sure if this would result in repeating lots and lots of code.
Also, I’m not sure cluttering up the ParentalBaseVM class with a method which returns the list of properties is great either. I was thinking of perhaps moving this to a new base class PropertiesListGenerator which can simply have a ParentalBaseVM passed to it, and returns a list of ElementVM. A derivation could be BasicPropertiesListGenerator, and a further derivation of this could be AdvancedPropertiesListGenerator. However, if not all ParentalBaseVM contain an "advanced" list and only the "basic" list then this may cause problems. My main aim here is to avoid repeating lots of code.
I have never used Delegates or Interfaces enough to truly understand them, so my coding skills aren’t really firing on all cylinders. Maybe they can help provide an elegant solution?
Any help is appreciated. I’m new to this and programming isn’t my full time job (evidently). If you see room for improvement in layout, readability, convention following, please feel free to suggest, I certainly will not be offended.
I need to loop through the properties of a custom object type that I'm getting back from the database and only show the columns that contain data.
This means I cannot simply bind the list of objects to the datagrid.
I don't want to loop through each object and see if the column is empty/null and determine in the UI to display it.
What I'm thinking is in my business layer before I send the object back I would send an IEnumerable back with only those columns that should be visible. Thus I was thinking of using Linq to Object to do this, but I'm not sure that would be very pretty.
Does anyone know of a solution that I could use without a ton of IF statements that I could do to check through a large object (30 or so columns) to determine what should be shown or not.
Foreach (CustomerData customerdata in Customers)
{
if (!customerdata.address.Equals(""))
{
dgvCustomerData.Column["Address"].visible = false;
}
//Continue checking other data columns...
}
I wish to avoid all of this in the UI and all the IFs...
I'm having a brain fart on this one can anyone help me?
Thanks
You could do the following to simplify it a bit
Action<T,string> del = (value,name) => {
if ( value.Equals("") ) {
dgvCustomerData.Column[name].Visible = false;
}
};
foreach ( var data in Customers ) {
del(data.address,"Address");
del(data.name, "Name");
...
}
Take a look at the .NET Reflection Libraries. You can use reflection to get ahold of all of an object's properties, and loop through them to find out if they are null or not. Then you could return a collection of KeyValuePair objects where Key = property name, and Value = true/false. You'd then use the keyvaluepairs to set column visibility...