I am using entity framework database first and extending the AutoGenerated partial classes. Is the following alright if I need to also set the property in my application based on certain scenarios? It just feels strange because I am usually setting a private property in my set, but don't think I need to here with EF.
public string FullName
{
get
{
return string.Format("{0} {1}", FirstName, LastName);
}
set
{
}
}
In my application FullName is a bound field in a grid. When I bind the grid from the database it works fine as a read-only property. But there is an instance where I have to dynamically create an objectlist of CustomerContact and pass it to another page in a Session variable and bind the grid in memory on the new page. Since the bound field for the same column in the grid on the new page needs to be FullName it seems like I have no option but to allow a Set on this property...
Based on the comments. No you should not leave it empty.
Think about it from a user point of view.
You can say MyThingy.FullName = "Fred Blogs". It compiles, it throws no exceptions and does absolutely nothing.
Other people's code, which includes your own in a couple of months, is hard enough to understand without drilling big holes in your cortex before you start.
To beef up from your last comment. No it doesn't make sense to have one class that has two completely different behaviours. There are lots of ways to deal with this sort of scenario, but making one object that implements both behaviours poorly isn't a good choice.
Hard to say which option would be best, but a DTO (Data Transfer Object) with a converter from and perhaps to the EF representation would be a much better solution than leaving a huge hole in the logic to fall into later.
Related
I want to create a class and its properties on run time, the properties will be like Year2001, Year2002, Year2003, Year2004, Year2005... I get these property names on run-time, I get them in a list. Later I need to use this class to create a list which I need to show in the kendo grid.I surfed a lot and thought of using ExpandoObject, but was unsuccessful.
If all properties will be of the form YearX and contain some information about or related to that year, then I would strongly recommend you (if at all possible) to go with something along the lines of an IList<YearInfo> where YearInfo is some object containing the info you need for every year, including an integer property indicating what year the object corresponds to. If you require these objects to be unique you could use an IDictionary<int, YearObject> or ISet<YearObject> instead.
Reflection can be powerful, but it it comes at the price of complexity and loss of type safety/compile-time checks. Avoid when possible.
Sounds to me like you are really wanting to a grid with grouping support. Your idea of having the system create a CLASS at runtime is not going to fly. Even if it were possible, which I doubt it is, it is absolutely the wrong approach.
Like I say - have a read about Grouping / Hierarchy on Grid Controls (Kendo grid example here), and maybe have a look at OLAP cubes as well...
Although you have had some answers I would also like to suggest an alternative way of doing this which is using DataTables. This is the approach I take when I have any "Dynamic" data sets that I want to present to the grid.
This is also the approach that Telerik themselves take with one of their code samples.
here are a couple of links to show them doing this to DataTables and Dynamic Objects
Grid Binding to Data Table
Grid Binding to Dynamic Objects
Personally I find the binding to Tables easier to deal with as I am used to dealing with Data Tables.
I have a quite big dilemma nowadays about general viewmodel design concepts. I mean general, like it's not exactly bound to a given language or environment: I had same dilemma when I wrote viewmodels for Winforms, WPF or KnockoutJS.
As a simplified use case, consider that I have a view where I have to select a country and a city from two select boxes. Both are represented in the database with a unique ID, a Name, and some other relevant information like - let's say - Population. Now imagine that I have to present a textual form of the currently selected data in for example the view's heading like "You've selected London, England". Now here is my two alternatives for creating a viewmodel, I will try to enumerate the pros/contras which I'm already thinking of below each version. The code is written in kind of pseudo way to be as generic as possible.
class RegionModel {
ID: number;
Name: string;
Population: number;
}
Version 1: Storing the selected object.
class MainView {
SelectedCountry: RegionModel;
SelectedCity: RegionModel;
SelectionInfo: string; // computed, should return the "You've selected ...." caption
Countries: List<RegionModel>; // datasource for country select
Cities: List<RegionModel> // datasource for city select
}
Pros:
Straightforward and easy to understand due to that the selected
item's type is the same as the selectable items' type.
Easy to compute such infos like "You've selected ..." because all the
members of the currently selected item are present directly.
Cons:
It holds more information than usually a consumer API needs. Usually
it needs only the ID.
If it's used in a client-side app, the whole selected object will be
returned to the server, consuming bandwidth.
If the consumer API needs only ID's (like in most cases), I have to
solve some kind of conversion before I pass it. In a web app probably
during serialization to JSON for example.
Version 2: Storing only the ID's of the selected items
class MainView {
SelectedCountryID: number;
SelectedCityID: number;
SelectionInfo: string; // computed, should return the "You've selected ...." caption
Countries: List<RegionModel>; // datasource for country select
Cities: List<RegionModel> // datasource for city select
}
Pros:
It's efficient in the way that it contains only the information which
is most likely needed by consumer APIs.
No additional conversion is needed, and efficiently can be passed
nearly "as is" to a server-side or other API.
Cons:
Not so straightforward and readable (in my opinion).
What about computing the info string? That's now much harder, I need
to grab the needed members from the selection source lists with a
search by the given ID, so it depends heavily on the consistency of
those lists (I mean the item must be present there).
I hope it won't be closed quickly as unconstructive. Any kind of advices, thoughts or experiences will be appreciated. Also, if the answer is "it depends", please try to give my some points where and when to use which.
UPDATE
I think my question was a bit unclear. I know about decoupling viewmodel from database entities, here I never mentioned database entities. I mentioned an "abstract consumer API". In a concrete scenario: if the API needs the selected items' Names, and my API needs only the IDs, which alternative should I choose, and where should do the conversion?
For example my server expects a data format like this (JSON):
{
"SelectedCountryID": 2,
"SelectedCityID": 5
}
and nothing else. How could I handle it in an elegant way? I would like to avoid repeating myself by doing a manual conversion.
Depending on how your datasources are implemented, it may make not difference: if you are retrieving the list of countries and cities, you can either store a reference to the selected value, to one of its fields or its index in the list.
Disregarding that, you should decouple your view model entities from your database entities and put into your view model ones only those fields required by the views. This way, your information traffic is minimized and your code is less affected by changes in the database.
EDIT following OP's update:
Talking about interacting with an API instead of a database, I think you can apply the same ideas, just replacing "database entities" by "service layer entities" (for instance, the JSON coming in/out your server). Take the returned data that into your view model objects, holding those attributes that you need. Obviously you also may need to store an id as you stated, when you'll need to refer to the same entity later on.
From a theoretical point of view, you should not include any other fields not consumed by the view, but you could do so depending on your requirements. For instance, in cases when you'll need to pass those fields back to the service layer and you don't want to query again by id to retrieve the service entity. However there are other alternatives to this (for example, some kind of cache), the exact balance depends on your requirements.
Base on MVVM pattern your viewModel should be an object with all properties which you need to display in view. ViewModel should be only used to be strictly binded to the view. Anyway your example it's not very good in my opinion. You shouldn't think about viewModel in case of storing something, please think more about presenting data.
Please remember that before you have data in database you have to insert it. So if you have some form with First Name and Last Name, user at first must fill this form and data must be insert into database, without it you don't have any ID.
To summarize in my opinion viewModel should have properties which you have to present to the end-user.
First off, I am new to programming (especially with C#) and thanks for your help.
I have a static web form with about 150 form objects (most checkboxes). I decided to go 1 record per form submission in the sql db. So, for example, question X has a choice of 5 checkboxes. Each of these 5 checkboxes has a column in the db.
I have the post page complete(working) and am building an edit page where I load the record and then populate the form.
How I am doing this is by passing a stored proc the id and then putting all the returned column values into the according object properties, then setting the asp control object to them.
An example of setting the asp controls to the selected value:
questionX.Items[0].Selected = selectedForm.questionX0
questionX.Items[1].Selected = selectedForm.questionX1
questionX.Items[2].Selected = selectedForm.questionX2
As you see, this is very tiresome since there are over 150 of these to do. Also, I just found out if the response is NULL then I get the error that it cant be converted to a string. So, I have added this line of code to get past it:
This is the part where I am populating the returned column values into the object properties (entity is the object):
if (!String.IsNullOrEmpty((string)reader["questionX0"].ToString()))
{entity.patientUnderMdTreatment = (string)reader["questionX0"];}
So, instead of having to add this if then statement 150+ times. There must be a way to do this more efficiently.
First of all, it seems that you are using string.IsNullOrEmpty(value), but this won’t check for the special DBNull value that is returned from databases when the data is null. You should use something more akin to value is DBNull.
The rest of your problem sounds complex, so please don’t be put off if my answer is complex too. Personally I would use custom attributes:
Declare a custom attribute
The following is a skeleton to give you the idea. You may want to use the “Attribute” code snippet in Visual Studio to find out more about how to declare these.
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
public sealed class QuestionColumnAttribute : Attribute
{
public string ColumnName { get; private set; }
public QuestionColumnAttribute(string columnName)
{
ColumnName = columnName;
}
}
Use the custom attribute in the entity class
Where you declare your entity class, add this custom attribute to every field, for example where patientUnderMdTreatment is declared:
[QuestionColumn("questionX0")]
public string patientUnderMdTreatment;
Iterate over the fields
Instead of iterating over the columns in the reader, iterate over the fields. For each field that has a QuestionColumnAttribute on it, get the relevant column from the reader:
foreach (var field in entity.GetType().GetFields())
{
var attributes = field.GetCustomAttributes(typeof(QuestionColumnAttribute), true);
if (attributes.Length == 0)
continue;
object value = reader[attributes[0].ColumnName];
if (!(value is DBNull))
field.SetValue(entity, value.ToString());
}
For the first part of your question where you set the ASP controls, you can use a similar strategy iterating over the fields of selectedForm, and this is probably simpler because you don’t need a custom attribute — just take only the fields whose name starts with “questionX”.
this is a quick & easy way of doing it.. there are some suggestions to investigate LINQ, and I'd go with those first.
for (int i = 0; i < 150; i++)
{
if (!String.IsNullOrEmpty((string)reader["questionX" + i.ToString()].ToString()))
{entity.patientUnderMdTreatment = (string)reader["questionX" + i.ToString()];}
}
... though this wouldn't be any good with the
questionX.Items[0].Selected = selectedForm.questionX0
questionX.Items[1].Selected = selectedForm.questionX1
questionX.Items[2].Selected = selectedForm.questionX2
lines
so I hear two questions:
- how to deal with null coming from IDataReader?
- how to deal with multiple fields?
Lets start with simple one. Define yourself a helper method:
public static T IsDbNull<T>(object value, T defaultValue)
{
return (T)(value is DBNull ? defaultValue : value);
}
then use it:
entity.patientUnderMdTreatment = IsDbNull<string>(reader["question"], null);
Now how to map entity fields to the form? Well that really is up to you. You can either hardcode it or use reflection. The difference of runtime mapping vs compile-time is likely to be completely irrelevant for your case.
It helps if your form fields have identical names to ones in the DB, so you don't have to do name mapping on top of that (as in Timwi's post), but in the end you'll likely find out that you have to do validation/normalization on many of them anyway at which point hardcoding is really what you need, since there isn't a way to dynamically generate logic according to the changing spec. It doesn't matter if you'll have to rename 150 db fields or attach 150 attributes - in the end it is always a O(n) solution where n is number of fields.
I am still a little unsure why do you need to read data back. If you need to preserve user's input on form reload (due to validation error?) wouldn't it be easier/better to reload them from the request? Also are entity and selectedForm the same object type? I assume its not a db entity (otherwise why use reader at all?).
Its possible that there are some shortcuts you may take, but I am having hard time following what are you reading and writing and when.
I recommend using the NullableDataReader. It eliminates the issue.
I have a table in my database called "OrderItemType" which has about 5 records for the different OrderItemTypes in my system. Each OrderItem contains an OrderItemType, and this gives me referential integrity. In my middletier code, I also have an enum which matches the values in this table so that I can have business logic for the different types.
My dev manager says he hates it when people do this, and I am not exactly sure why. Is there a better practice I should be following?
I do this all the time and I see nothing wrong with this. The fact of the matter is, there are values that are special to your application and your code needs to react differently to those values. Would your manager rather you hard-code an Int or a GUID to identify the Type? Or would he rather you derive a special object from OrderItem for each different Type in the database? Both of those suck much worse than an enum.
I don't see any problem in having enum values stored in the database, this actually prevents your code from dealing with invalid code types. After I started doing this I started to have fewer problems, actually. Does your manager offer any rationale for his hatred?
We do this, too. In our database we have an Int column that we map to an Enum value in the code.
If you have a real business concern for each of the specific types, then I would keep the enum and ditch it in the database.
The reason behind this approach is simple:
Every time you add an OrderType, you're going to have to add business logic for it. So that justifies it being in your business domain somewhere (whether its an enum or not). However, in this case having it in the database doesn't do anything for you.
I have seen this done for performance reasons but I think that using a caching mechanism would be perferable in most cases.
One alternative to help with the synchronization of the database values and the business logic enum values would be to use the EnumBuilder class to dynamically generate a .dll containing the current enum values from the database. Your business logic could then reference it, and have intellisense-supported synchonized enum values.
It's actually much less complicated than it sounds.
Here's a link to MSDN to explain how to dynamically build the enum.
http://msdn.microsoft.com/en-us/library/system.reflection.emit.enumbuilder.aspx
You just have to sub in the database access code to grab the enum values:
One more vote for you, I also use mapping database int <-> application enum, in addition, I usually describe my enums like this:
public enum Operation
{
[Description("Add item")]
AddItem = 0,
[Description("Remove item")]
RemoveItem = 1
}
which leaves me absolutely free to add new values without need to change database and with a very short workaround I can work i.e. with lists containing descriptions (that are very strongly tied to values!) - just a little bit of reflection reaches the goal!
In code, you can typically just add a property like this:
public class Order
{
public int OrderTypeInt;
public OrderTypeEnum OrderType
{
get { return (OrderTypeEnum)OrderTypeInt; }
set { OrderTypeInt = (int)value; }
}
}
I'm trying to use ASP.NET's Repeater objects to loop over properties of an object.
For example... I have an ObjectDataSource to grab object "Program" by ID...
Program has properties such as Program.Stakeholders and Program.Outcomes which are Lists of "Stakeholder" and "Outcome" objects.
Now... what I'd really like to do is use the Repeaters to target these Properties and loop over the lists they contain. However, as far as I know I'd have to set up a separate data source for each one, tied to an individual method to retrieve each list.
Can anyone provide a better way to use these Repeater objects, or point me at some resources which would help? If this doesn't make sense I can try to clarify it more.
Using the built-in ObjectDataSource mapping up a separate datasource for each item is probably the only straightforward way (and the only way that's easy enough to be worth the effort...).
Is it a requirement that you use the ObjectDataSource, or can you choose a different way to get the data from the storage? I would recommend either using Entity Framework (which imho rocks) or creating your own custom types to which you get the data with a custom designed DAL (which is a lot more work than using EF, but if you're, like some, concerned that EF is still in infancy this might be your option).
In either case, you'll end up with a C# class called Program, which has properties of type IEnumerable<Stakeholder> and IEnumerable<Outcome> called Stakeholders and Outcomes respectively. You can then use these as datasources for the item repeaters and set them in the ItemDataBound event of the ProgramRepeater, maybe something like this:
protected void ProgramRepeater_ItemDataBound(object sender, ItemDataBoundEvent e) {
Program dataItem = (Program)e.DataItem;
Repeater stakeholderRptr = (Repeater)e.Item.FindControl("ProgramRepeater");
Repeater outecomeRptr = (Repeater)e.Item.FindControl("OutcomeRepeater");
stakeholderRptr.DataSource = dataItem.Stakeholders;
stakeholderRptr.DataBind();
outecomeRptr.DataSource = dataItem.Outcomes;
outecomeRptr.DataBind();
}
This is assuming that you're using ASP.Net WebForms, of course. In ASP.Net MVC it is even easier - you just send the Program object to the View as the Model object, and loop through its Stakeholders and Outcomes in a couple of nested for loops directly on the View.
Note: All code is provided as is, and I do not guarantee that it will run as expected or even compile. It is just to give you an idea of what to make your code do - not necessarily the exact code you need to solve your problem.