c#:
In an attempt to sparate my database, business logic and GUI, I am trying to have only my Data Object having database goodies. So, for example, my GUI app wants to get a list of users to put ito a combo box. It makes a call, 'GetListOfUsers'. The Business layer has a function that would return a <List>. It calls the data object which does the SQL. This would maybe call 'GetUserList'. The data object at the moment, returns a DataView, Tht's bad, because my Business Layer then needs to iclude System.Data... How can I rather return the data from the Data Object, without using some fr of data class??
Well, if you don't want to use System.Data then the obvious choice would be to use custom classes to represent your data (instead of DataTable), but I'm not sure that I'd consider using System.Data an undoing... it is going to be in the GAC of any standard installation etc. Actually, my biggest gripe here would be that a view (DataView in your case) isn't really a self-supporting entity. I would tend to return the model itself (DataTable or DataSet (probably typed), or [better IMO] a set of SomeBespokeClass instances (perhaps list, array or collection)). Although IMO, DataTable will always inherently be too close to the database layout for my liking; I'm a bit fan of using bespoke classes; partly for this reason, but for lots of others too. When DLinq will be of obvious interest here... but my worry here is that the default implementation again puts too much database knowledge into the entities (via the attributes). Marc
GAC = global assembly cache; the list of assemblies that can be accessed (without any additional deployment requirements) by any application on a machine. It isn't for me to give a red/green light to DataSet... it depends on your requirements and usage... some people love them; I'm not a fan, but I also wouldn't say "never" to them. But if you are using a DataTable based architecture, then I would fully expect to reference System.Data at every tier. Re bespoke class... by virtue of discussing DataView, I assume you are using a DataSet / DataTable implementation for your data. Another option (with pros and cons) is to forget DataTable etc, and use classes that represent your entities... i.e. (not all details shown) public sealed class Customer { public string Name {...} public string Rererence {...} public OrderCollection Orders {...} } Fundamentally, however- *how* you hold your data, and separation into layers, are two different things. I applaud your separating them, but it isn't necessarily compulsory to ditch DataTable as a solution. In this scenario (with an established DataTable code-base) I would probably return a "typed" DataSet/DataTable from my business layer etc; this allows full visibility of what the data will hold, and allows for simpler serialization etc if needed later on. With a class-based approach, you then of course need some way of getting this in-and-out of the database, since the ADO.Net adapters aren't going to help you. You can choose to do this manually, or you can use "ORM" (object relational mapper, such as NHibernate) software to write this plumbing code for you. Or in the next major CLR version, a new technology called DLinq might fill this role. Very early days yet. Marc
Thanks Jon - useful info. Other than a few quick dabbles with the new beta, I haven't played with any of the Linq variants yet; do you know if the configuration concept is documented anywhere? I know where you are coming from with your attributes comments, but I suspect (for various reasons) that an external configuration route would better fit my environment. Marc
[quoted text, click to view] On May 8, 7:50 am, "Marc Gravell" <marc.grav...@gmail.com> wrote:
<snip> [quoted text, click to view] > DLinq will be of obvious interest here... but my worry here is that > the default implementation again puts too much database knowledge into > the entities (via the attributes).
I believe there will be ways of configuring the entities without using attributes, but using an XML configuration file instead. Personally, using other ORM systems with the same sort of options, I've always found that the simplicity of using attributes outweighs the elegant database separation of using config files. The question to ask is in which situations you really need that level of decoupling, and how likely they are to crop up. Jon
THanks Marc. Sorry, what do you mean by a bespoke class. (Sorry fot my ignorance here). Also, as this is me dabbling in a more layered design, as opposed to everything in the GUI layer, what is meant by GAC? Are yo saying it's OK to have System.Data in your business layer? The one with the 'User' Class, then 'Account' class etc? And then allowing the Data objects to return DataSets isn't a bad thing? If so, and if this accepted practise, then.. great! Away I go.
Thanks again for all that. Just to clarrify, I was under the impression that returning DataSets from the data objects, to the business layer, and then to the GUI layer was not good, as this would make the business layer and GUI dependent on the database. So if you made a change to the database, changes would be needed in all layers. Is that not the case? Or is that just the way it is? Could I put a basic example past you, and see if you can 'code' it? Please note, my OOP is basically non-existant, but I need to learn the main basics in 40 days, as I start a new job, and am trying to be useful before I start. I come froma Dlephi background, and didn't use OOP much at all. I have a Login form. Username and Password. GUI layer. OnClick, it makes a call to my Security class, to a method called 'CheckLoginCredentials for example. Security sec = new Security(); int UserID = sec.CheckLoginCredentials (edUsername.Text, edPassword.Text); if (UserID > 0) { ..... } Business Layer: public int CheckUserCredentials ( string strUsername, string strPassword ) { User user; // Create the User object, that will hold all the User info of the logged in person. UserDataObject UDO = new UserDataObject(); user = UDO.GetUserIDFromUsername ( strUsername, strPassword ); if (user<>nil) // Check if there is such a user. { return user.ID; // Return the UserID } return -1; // No such user } Data Layer: public user GetUserIDFromUsername ( string strUsername, string strPassword ); { Create SQLConnection; Create all the required SQL stuff. execute "SELECT userid, username, password, firstname.... FROM dbo.[Users] WHERE username = @username and password = @password"; create a user object and populate it based on what we get back from the database; if recordcount > 0 then return user; else return nil; } Could you tell me if my idea of how it SHOULD work is OK, and also, how I would rather use a DataSet instead?
[quoted text, click to view] > as this would make the business layer and GUI > dependent on the database. So if you made a change to the database, > changes would be needed in all layers.
That is very hard to answer; on its own, using DataSets doesn't tie the GUI and BL *directly* to the database - but in *any* architecture there is going to be a dependency... Likewise the relationship between database changes and code changes - it depends on the change ;-p It could require no changes; maybe a rebuild; maybe an overhaul - but that isn't directly tied to how you hold your data. A DataTable is always going to be a bit closer to the database - but you have some opportunity to play with things at the adapter level. Your idea of how things /should/ work seems broadly OK - except personally I might just throw an exception for invalid credentials [either option would work as long as documented], and I would never hold "password" in a database ;-p Maybe a hash... but that is off topic. I'm not sure why your data-layer would go to the bother of building a "user" object just for the BL to use a single property... either bubble "user" all the way, or simply return something simpler from the data layer [unless your data layer need to satisfy various callers]. And the create-to-call-once UserDataObject usage seems to cry out for a static method. The magic number (-1) again might be better handled with an exception, but it works as-is. Marc
Thanks Marc. Will change that to sue an exception then. Sounds like a best-practise to get used to. Not sure what you meant by 'bubble' user. I was thinking that on login, the user object would be created and would hold simple details about the logged in user, so, for example, on each screen, at the top, or something, there's a message: 'Logged in as: Craig Lister', or something more useful than that. :) Can't think of anything, but the idea here is for me to have a persistant object that I can refer to at any time, with maybe an Update function, which maybe got used as an Auditing function, logging the history of the user. "Logged in", "Updated an account", or something like that. Scetchy idea, but just trying to use different ideas to learn. :) So, when you say 'bubble user', do you mean what I am trying to do? A user object that is basically there all the time that I can then get user.ID when ever I want it, or maybe user.LogEvent("Logged in successfully"); type stuff?
[quoted text, click to view] On 9 May, 05:11, Marc Gravell <marc.grav...@gmail.com> wrote: > And the create-to-call-once UserDataObject usage seems to
cry out for a static method. Sorry Marc, could you elaborate on this one? How would you impliment this? No class?
I just meant "pass it along to the caller" (rather than returning just the ID) - so yes, this is what I meant, since this would be required for your UI to get hold of the object. Note that you might also (OT) want to read about "Principal"s; the "Principal" for a thread contains an abstract representation of who the user is - which makes it possible for any tier to ask "who am I representing, and what can I do?" without (for instance) your date-tier having to know about the login implementation that your UI uses. Using an OO aproach, your "user" object could happily implement IPrincipal and IIdentity - or there are some simple implementations in the framework - either way you might want your UI to try and log in, and then (if successful) set the Thread.CurrentPrincipal. Just a thought... Marc
Ref: [quoted text, click to view] > Security sec = new Security(); > int UserID = sec.CheckLoginCredentials (edUsername.Text, > edPassword.Text); .... > UserDataObject UDO = new UserDataObject(); > user = UDO.GetUserIDFromUsername ( strUsername, strPassword );
In both cases we are creating an object just to make a single call to a method. I doubt whether either of Security or UserDataObject provides any instance "state" (local properties etc that might change for that instance over time) - just methods. In this case, you still have a class (for somewhere to put the code), but you don't need any instances ("new ..."). e.g. public class Security { public static int CheckLoginCredentials(...) {...} // as before } Note the "static" keyword; this tells the compiler that this method is not specific to any single instance, but rather exists against the *type*; now I can call: int userId = Security.CheckLoginCredentials(...); without a "new" etc. Less typing for you, and fewer objects for the garbage-collector to have to look at. In 2.0 you can mark the whole class as static ("public static class"), which will enforce that all members are static, and will remove the default constructor etc. Sometimes, you want static-style functionality, but for some reason you also need to meet an agreed interface definition; static methods can't be used in interfaces, so in this case the "singleton" pattern can be useful. I won't detail this for now - just mention it (and one of its uses) so that you know of its existance should it sound a likely fit. Marc
Don't see what you're looking for? Try a search.
|