I would like to learn more about the appropriate way to use classes when using a database. Here is the example of what I think is ok.(Using C# and SQL Server if curious)
I Have a table called "Features" and most of the columns in it hold IDs(Foreign keys). To load that table into the application, I create a "DBFeatures" class to hold all the columns. Next I should have a regular "Features" class that has the actual values of all properties in "DBFeatures" class. "Features" class would have a method that opens a connection to the database to grab all the right values with the given IDs. Then The "Features" class can be used as is.
The same would go in reverse, I create an object of "Features", then it converts it into a "DBFeatures" class which gets passed to the database when INSERTING.
Is this the right way to go about this? What other options would be better? The only other option is just have one class, "DBFeature" class, and when I create an object of that class, each time a property is set or gets, it would have to access the database to get the value by providing an ID.
EDIT
I'll be using the data for forms. Most of the tables will be read only which will be stored into a list of objects which can then be used with Controls(like the data source of a combobox). Also I want to be able to load user input into a class that would be outputed to a table in the database.
A lot of planning on how to do something depends on your implementation which you are not providing. What are you planning to do with your objects? Is it for a report? Do you need to manipulate the values?
I'm going to assume you are going to be manipulating the data in which case you should have a class that opens the database and loads it into classes that represent it.
The class can have properties that correspond to the columns and then you can have a list of the class to represent the rows.
This is just one example of how to do it but its impossible to say without knowing what your intent is and having more details.
It looks like you need ORM like Entity Framework.
Related
I have two tables wherein i want to insert the data to the first one (MASTER) and the other table would copy some of the data from the Master table..
Here is my representation:
I want the Ven_ID to also be reflected in my Workflow table Workflow_ReqID automatically.
I know this is possible but can someone give me the directions ?
You can have a trigger/procedure at database level which will insert data into your second table. It depends if this table is updated anywhere else.
There are two ways to go about it :
Use SQL Server AFTER INSERT Trigger. You can find plenty of resources off the internet on how to create a trigger and how to declare its definition.
Another way to do it is through entity framework (I see you have tagged entityframework)
I will explain how you can use entity framework
Let's say you have the entity representing the WorkFlow table as WorkFlow and the table representing Ven (may be vendor) as Vendor.
Since you are having required foreign key in the WorkFlow table of the Vendor primary key, you must have a backing stub for that i.e. your WorkFlow table must have a virtual navigational property of type Vendor i.e.
public class WorkFlow
{
//other properties
public virtual Vendor Vendor{get;set;}
}
you just have to create WorkFlow object and the Vendor object (either create a new or retreive from db) and just assign it to the workflow object i.e.
WorkFlowObj.Vendor = objVendor
and EntityFramework will take care of rest.
I would prefer this way.
Though using triggers is not bad, but only problem with them is when you have to deploy, you must also deploy them triggers and every time you make changes to them, you must take care of them too.
If you want Ven_ID and Workflow_ReqID to be same get the Vent_ID in the output parameter in store procedure and pass it to the second table insert statement.
Get last inserted id using SCOPE_IDENTITY() after insertion and add it to workflow table. To save db trip you can use sproc for that.
I have an EDM used to bring back a collection of "Product" entities within a DAL project. An MVC website project references and directly instantiates the ObjectContext and returns an IQueryable to the website for paging and displaying of Products.
This Entity, to simplify things, we'll say only has "ID", "Rate" and "Description" properties. I want to create another calculated property called "CostPerMonth" which will take an input from the website called "LoanAmount", and, again, to keep things simple, this "CostPerMonth" property will be made up of (("LoanAmount" * "Rate") / 12).
I can't help but feel this calculation should be done in the DAL project to make the code more reusable, as whereever this data is used, a "LoanAmount" will always be specified. The possible solutions I have had are below:
Create a partial class for Product, add a new property "CostPerMonth" to Product. In the website controller, when the data is returned, populate this new column by iterating through the returned data and doing the calculations?
Create a partial class for Product, add a new property "CostPerMonth" to Product. In the DAL project, create a helper class that has a method that accepts a "LoanAmount" parameter and returns a List. The trouble with this is I would need to materialize the data in order to do the calculations. The method could accept a "Skip" and "Take" parameter that could be used in the Linq query used to return the products?
Create a partial class for Product, add a new property "CostPerMonth" to Product. Add another tier to the solution using WCF web services, within the service method do the calculations and use REST to return the data to the MVC web site?
Any advice would be very much appreciated.
Best regards,
Mark
If we take a step back and actually breakdown what you are asking in your question it might be easier to explain my answer.
We have an object/entity named Products
There is a calculated field which will be (("LoanAmount" * "Rate") / 12)
CostPerMonth does not need to be stored in the database
So this calculated field is a business rule for the Product Entity. Given that you are using MVC, there is only one place where this code/logic can go and that is the model.
Given that your using EF It will sit in a non mapped/computed field and the code to give you an idea will look something like this....
[NotMapped]
public decimal CostPerMonth
{
get { return (LoanAmount * Rate)/12 ; }
}
I can go on for days about the problems about having fragmented business logic throughout various layers.
Now if you want your this logic to be consumed easily by other clients, you need to expose a service to do that. (you can use webAPI/service stack/ wcf, etc) it is really another entire question based on your needs. But the point here is that your logic is in one spot.
Suppose we have class PersonModel, user edits a detail form in the browser and hits the submit button.
How to write a controller logic to create an UPDATE SqlComand (no EF) and update only those of fields from class PersonModel (FirstName, LastName, Age...) which have been changed.
What should be an argument of the /Person/Edit/<id> controller?
You don't do anything special to your MVC code, and you don't add any special URL parameters.
If you only want to update the changed fields, then you have to write a lot of code. You have to get the current record, compare each of your models fields to the records fields, figure out which ones have changed, then you have to construct a SQL statement based on the changed fields, then update it, making sure to use optomistic record locking to insure the field has not changed between when you retrieved it and when you update it.
This is probably going to be a couple hundred lines of code. Or it could be one line of code if you were using an ORM.
Also, keep in mind you need to use parameterized statements as well, to insure against a SQL injection attack (something you get for free in an ORM as well).
Good luck, I certainly am not going to write it.
What I would suggest is that you don't use the generalized PersonModel which I assume is a 1:1 representation of your data model. You should create a watered down view model of with only the fields you care about. Then use something like AutoMapper to map the ViewModel back to your DomainModel.
Here is a reference on how to use AutoMapper for such a scenario.
How to cross map objects using AutoMapper
You may use Linq and let the datacontext do everything for you.
In the Model you just create your data class with the linq queries for the update, retrieve the object, set all the values that have been passed from the view in the object you've retrieved (you'll have to do this anyway, since the pattern decouples the view from the model | Remember too, that MVC implements observer for letting the view to know about changes in the model, so you can't know what was modified in the view from the controller), and then you call the DataContext.SubmitChanges(); method. The data context will do the job in its own. It will know what to change and modify and will make the most performant query.
Is it possible to map a class with each property stored as a row in the table, not a column. The scenario is where we persist global options to the database. We store the options in an 'Options' class that has a property per option, i.e. "Expand Menu", "Save on Exit" etc.
Rather than store each option in its own table column, we would simply like to have a table with each of the class properties stored as a new row, identified by a Enum.
Is this possible?
(C# Winforms)
Using NHibernate's EntityMode.Map might help solve this problem. It does mean that you might have to put your global options in a Dictionary collection, but you can always implement an Option class that abstracts the underlying Dictionary.
NHibernate provides the ability to map a Dictionary dynamically to a table. See NHibernate's reference on Dynamic Models
Edit: I am using SqlDataAdapters to fill the data sets. Sorry--I should have been more clear.
I'm working on a project where I need to fill a number of strongly-typed data sets with information from stored procedures. Right now, I have a generic method in my data access layer:
public static DataSet FillDataSet(DataSet dataSet, string storedProcedureName, Dictionary<string, string> parameters);
The problem with this is that I need to establish mappings between the returned recordsets from the stored procedure and the tables in my data sets. I have come up with two options for doing this:
Add a new formal to my FillDataSet method (KeyValuePair<string, string>[] mappings) that would provide the information for the table mappings.
Create a DataSetMappingFactory that would take a DataSet as a parameter and then add the appropriate mappings based on its type. If it were an unknown type, then it wouldn't add any mappings. Then, it would return the DataSet to the FillDataSet method.
Do any of you have other thoughts about how I could approach this problem? Also, does anyone want to weigh in on an approach that would be best in terms of object-oriented design?
The first question I'd ask is: do I really need to do this at all? The typed DataSet designer already gives you a tool for defining the mapping between a stored procedure and a DataTable. If you design your DataSet with care, you already have a Fill method for every DataTable. Does it make sense to reinvent that wheel?
I think it might. It's really cool that there's a way to maintain that mapping, but everything in that mapping is frozen at compile time. If you want to change the mapping, you need to rebuild your assembly. Also the typed DataSet design doesn't deal with stored procedures that return multiple result sets. If you want to generically map parameters and values, you have to use reflection to get the argument lists from the Fill methods. It may be that if you look at those factors (and others I'm not thinking of), working with the existing tool isn't the way to go.
In that case, it seems to me that your goal is to be able to populate a DataSet from a series of stored procedures with code that knows as little as possible about the implementation details. So this is a process that's going to be driven by metadata. When you have a process driven by metadata, what's going to matter the most to you in the long run is how easy it's going to be to maintain the metadata that the process uses. Once you get the code working, you probably won't touch it very much. But you'll be tweaking the metadata constantly.
If I look at the problem from that perspective, the first thing I think to do is design a typed DataSet to contain the metadata. This gives us a bunch of things that we'd otherwise have to figure out:
a persistence format
a straightforward path to building a bound UI
an equally straightforward path to persisting the metadata in a database if we decide to go down that road
an object model for navigating the data.
In this DataSet, you'd have a DataSetType table, keyed on the Type of each typed DataSet you intend to be able to populate. It would have a child StoredProcedures table, with a row for each SP that gets called. That would have two child tables, Parameter and DataTableType. There would be one DataTableType row, ordered by ordinal position, for each result set that the SP's expected to return. The DataTableType table would have a child ColumnMapping table. It's in that table that you'd maintain the mappings between the columns in the result set and the columns in the table you're populating.
Make sure all of your DataRelations are Nested, and that you've given rational names to the relations. (I like FK_childtablename_parenttablename.)
Once you have this, the class design becomes pretty straightforward. The class has a reference to the metadata DataSet, the Connection, etc.,, and it exposes a method with this signature:
public void FillDataSet(DataSet targetDs, Dictionary<string, Dictionary<string, KeyValuePair<string, string>> parameterMap);
You start by using the targetDs's Type to find the top-level DataSetType row. Then all of the private methods iterate through lists of DataRows returned by DataTable.GetChildRows(). And you add an event or two to the class design, so that as it performs the operation it can raise events to let the calling application know how it's progressing.
Probably the first place I'd expect to refactor this design is in giving me more fine-grained control over the filling process. For instance, as designed, there's only one set of SPs per typed DataSet. What if I only want to fill a subset of the DataSet? As designed, I can't. But you could easily make the primary key of the DataSetType table two-part, with the parts being DataSet type and some string key (with a name like SPSetName, or OperationName), and add the second part of the key to the FillDataSet argument list.