|
led mike wrote: If the user interacts with it, it is a presentation object.
Class user, not application user. I guess I can't express my problem better.
How it works in code is like this:
WidgetsBLL widgetsLogic = new WidgetsBLL();
Widget widget = widgetsLogic.GetWidgetById(13);
Now you can access various fields of the widget:
widget.WidgetId
widget.FriendlyName
And so on. You also have a User class, which has properties such as FirstName, LastName, etc.
I need to present combined data, so in one row we have WidgetId but also user's FirstName - as you can see this data belongs to two different classes. I am not sure whether to design a third class and include both Widget and User by composition or to do something else. That is my problem I tried to describe.
Kind regards,
Pawel Krakowiak
|
|
|
|
|
Pawel Krakowiak wrote: include both Widget and User by composition or to do something else
Composition is reasonable.
You are asking an Object Oriented Analysis and Design question. Without seeing your analysis and existing design it's difficult to offer any meaningful advice but under the heading of General points:
Are you using interfaces?
and...
Pawel Krakowiak wrote: Now you can access various fields of the widget:
widget.WidgetId
widget.FriendlyName
See this article[^]
|
|
|
|
|
It seems to me you should be binding your datagrid to
Widget.WidgetId | Widget.WidgetName | Widget.Owner.LastName | Widget.Owner.Email
This is a fairly important distinction - the example you gave doesnt appear to take advantage of the relationship between Widgets and Users. You might not want your BLL to know about the exact FK relationship in the database, but the fact that Widgets have an Owner is part of your domain, and there is no escaping that.
How you implement these properties on the Widget class is up to you.
You might also want to consider using a tool that handles the database mapping for you. My company (linked in my signature) provides such a product, which is free for non-commercial use.
|
|
|
|
|
Mark Churchill wrote: It seems to me you should be binding your datagrid to
Widget.WidgetId | Widget.WidgetName | Widget.Owner.LastName | Widget.Owner.Email
Yeah, I redesigned the application, so now my business objects make more sense.
I could write a SQL query (stored proc) which would return data from joined tables, then create another Table Adapter and BO. But this doesn't look good to me in terms of design. First rule is you should not update the business layer to meet the UI requirements, it should be exactly the opposite. And that's why I don't like the idea of creating a new BO just for displaying statistics in a GridView in the presentation layer.
My problem (at least a similar one) was already discussed at ASP.NET Forums[^].
Thanks.
Kind regards,
Pawel Krakowiak
|
|
|
|
|
Pawel Krakowiak wrote: First rule is you should not update the business layer to meet the UI requirements
I never heard that rule, can you provide a link to your source?
|
|
|
|
|
led mike wrote: I never heard that rule, can you provide a link to your source?
It's called common sense. The whole idea behind decoupled modules is to make them pluggable, so you can throw out your ASP.NET UI and plug in WinForms and it will still work, because the business layer stays the same. If you start adding UI related stuff to your BOs you are coupling those two layers again. In the end when you want to switch the UI you have to rewrite the BOs or end up with BOs hanging in the air (not used anymore) and writing new ones.
I guess the size of your project is important and its particular requirements, right? Follow the ASP.NET Forums discussion if you want, I am just agreeing with some opinions there.
Kind regards,
Pawel Krakowiak
|
|
|
|
|
Pawel Krakowiak wrote: It's called common sense.
I see you are joking but seriously I have my own Number One Rule: Don't make stuff up.
What I mean by that is that so much information is available now there is no need to in 99.9% of the work I do.
Pawel Krakowiak wrote: and its particular requirements, right?
Yes requirements, and analysis, are the key in your problem. What I mean is, if you have discovered a missing requirement or incomplete analysis then of course it might require a change in any layer(s) or part(s) of your system or even design dependencies forcing a refactoring to alter the design.
Pawel Krakowiak wrote: but now I came to the point where I must display combined data in a GridView
Certainly that could have been anticipated but that is what iterative development is about. Understanding that we are not always able to have all the requirements before we start designing or that our analysis might be flawed or have holes. When these issues occur what we hope to find is that our design supports adding the new feature but even that is not always possible.
|
|
|
|
|
led mike wrote: I see you are joking but seriously I have my own Number One Rule: Don't make stuff up.
I shouldn't have said 'rule', rather 'suggestion' or 'good practice'. Of course there are no rules which say you can't include UI stuff in your business layer.
led mike wrote:
Certainly that could have been anticipated but that is what iterative development is about.
In this particular project the statistics were to be supported by an external system, but we had to put the website in an IFrame (which wasn't planned) and the external system doesn't work that way, so I had to write my own statistics "engine" and now I need to include a couple of stats pages. But this doesn't mean I should be adding Business Objects which represent "a statistic", which really consists of a few fields taken from two objects which already exists - GUI should do the job - it already can get the objects and should take care of combining and displaying them. I was looking for somebody to tell me maybe that creating a new BO just for this purpose was OK, even though I didn't like it, hence my original question.
Anyway, as you originally said, this would be difficult without showing my classes. I asked a theoretical question.
Oh, by the way - regarding the 'accessors are evil' article - you must have public properties in order to bind ASP.NET controls to data. .NET Framework itself is full of properties, sometimes they are more readable in code and easier to use, but as someone (maybe it was in that article?) said - working for Sun or Microsoft doesn't magically improve your skills.
Kind regards,
Pawel Krakowiak
|
|
|
|
|
I don't totally agree here. Implementation aside, if you were to draw me an ERD then you would agree that Widgets have an Owner of type Person. A person owns none or more widgets. Regardless of whether you have a ASP.Net/Webforms or command line, this relationship exists.
You business layer should also have Widget.Owner, and likely Person.Widgets[]. Sure, your database reflects this as a foreign key. Thats fine. Call it a coincidence. Your BL is based off the ERD, your database is also based off the ERD.
They do both represent the same things, expect them to be similar.
|
|
|
|
|
Mark Churchill wrote: You business layer should also have Widget.Owner, and likely Person.Widgets[]. Sure, your database reflects this as a foreign key. Thats fine. Call it a coincidence. Your BL is based off the ERD, your database is also based off the ERD.
Mark, but this leads to a circular dependency, i.e. a Person has Widgets collection, each widget has an Owner, which is a Person, which has a Widgets collection, each widget has an Owner, which is a Person, which has a Widgets collection, each widget has an Owner...
You know what I mean?
Currently my idea is to have a User class, which contains WidgetList (inherits from List[Widget]), but Widget only has UserId as its owner, not the whole object. If you need the owner, you can retrieve it from UserManager (another class which manages objects of type User). This, of course, means that ASP.NET databinding is not so easy, because I need to add some TemplateFields and fill them in in GridView event handlers.
Kind regards,
Pawel Krakowiak
|
|
|
|
|
That circular dependancy seems to be correct behaviour to me. What is important is that the User and the Widget are the same instance every time around.
I would expect "somePerson == somePerson.Widgets[0].Owner".
This is similar to say a heirachy of Controls on a page. "someThing.Controls[0].Parent" could have you going in circles in a similar manner.
Diamond Binding will give you a Owner property on the Widget class of type Person, and an IList<widget> on the Person class. The actual implementation of IList depends on whether you have picked lazy-loading. You could also configure an IDictionary<x,widget> where x is a property of Widget that is unique per Person.
Think of it this way: Is it incorrect of me to ask "Who is your father's son's father's son's father?". It might be inefficient of me to ask that, but the query has an answer in your problem domain.
|
|
|
|
|
So, you suggest to have an accessor like this:
<code>private int _ownerId;
public User Owner
{
get
{
return UserManager.GetUserById(_ownerId);
}
set
{
_ownerId = ((User)value).UserId;
}
}</code>
User = Person, I currently have that class named User, although it conflicts with a class from .NET Framework sometimes, so renaming it to Person is a good idea.
This is a simplified example, but something like the above? This would allow to bind easily the property in ASP.NET, like "User.Owner.FullName", but still wouldn't endlessly load objects, right?
BTW. Is DiamondBinding an ORM? I have currently a license for EntitySpaces[^], but am not using it at the moment. The way how ORMs present the objects looks like more fitting for the DAL rather than BLL... But this is an another discussion.
Kind regards,
Pawel Krakowiak
|
|
|
|
|
Yep that seems ok. If the UserManager has a caching strategy of some sort then you won't have any problems with circular references giving you duplicate objects either. (Although theres a redundant cast in that setter ).
You could also keep a local cache of the child object - this would be more efficient when pulling out say User.Owner.FirstName + User.Owner.LastName - it would avoid two trips to the UserManager. Of course with any caching you have stale-cache issues to solve
As for lists, you can have your Widget collection implement IList<widget>, but not actually retrieving the objects until iterated or an item requested (lazy loading again).
Diamond Binding is an ORM and definition generator. It follows the ActiveRecord model, so its less data-model oriented than other ORMs - so you are mainly dealing with objects at a business level: Customer c = Customer.Find(primaryKey); IList/Customer/ l = Customer.FindAll(); (Edit: Forum broke my generics!) Theres an example on the product page here[^]. Give the Personal Edition a try if you like, theres no functional difference between it and the Professional / Enterprise Editions. We aim to handle the entire data access requirements and just let you build business logic on top of the model we give you.
|
|
|
|
|
Mark Churchill wrote: If the UserManager has a caching strategy of some sort then you won't have any problems with circular references giving you duplicate objects either.
I am not sure how to do this yet, can you point me to some articles?
Mark Churchill wrote: Although theres a redundant cast in that setter
Yes. I thought value was of type object, forum doesn't give me any guidelines.
Thanks for all your comments so far.
Kind regards,
Pawel Krakowiak
|
|
|
|
|
A really simplistic implementation would be to add the caching to your UserManager.Load(object pk). Check the cache, and if its in the cache then return it. Otherwise load the object's data and add it to the cache.
You can use a Dictionary for your cache for prototyping. ASP.Net provides a cache (I think you can safely use this outside of the web framework too) that you can add objects to with a key and an expiry.
You might want to add some way of forcing a reload of an object as well. To be honest though if you are writing your own data layer you are going to have to draw the line for features somewhere. I haven't done a KLOC count on Diamond Binding for a while - but I'm guessing its approaching the millions, and thats not including NHibernate
|
|
|
|
|
Slightly OT... But I was wondering, how does Diamon Binding differ/compare to the ADO.Net Entity Framework coming up in VS2008?
Me: Can you see the "up" arrow?
User:Errr...ummm....no.
Me: Can you see an arrow that points upwards?
User: Oh yes, I see it now!
-Excerpt from a support call taken by me, 08/31/2007
|
|
|
|
|
I guess the cheeky reply is that Diamond Binding is avaliable now, and is mature, and leveraging Hibernate, which is also decades mature. Last I heard the Entity Framework was dropped from Orcas and was going to be released "out-of-band" sometime in the first half of 2008.
EF, like a lot of ORM products tends to be very heavyweight and favours model-first development. It is a very complex product, however I think the key feature that everyone is interested in is LINQ to Entities. LINQ is not really EF specific. After the product becomes more mature, we will look at including LINQ support in Diamond Binding. Although we find that Expressions and HQL support cover most use cases sufficiently at the moment.
DB is designed with simplicity in mind, and is geared towards keeping your business objects synchronised with the database schema, and handling everything in between for you. If the schema changes, its a one-click synchronisation. One aim is to stop developers getting bogged down in mapping, and just let them add business value to the application!
|
|
|
|
|
Mark Churchill wrote: A really simplistic implementation would be to add the caching to your UserManager.Load(object pk). Check the cache, and if its in the cache then return it. Otherwise load the object's data and add it to the cache.
Sure, but I am concerned with the stateless behavior of web application / HTTP. As far as I know when the page is pushed back to the calling browser, it is disposed of and doesn't exist anymore, hence I am not sure how to cache data, otherwise than in some process which runs all the time on the server. Honestly, I haven't been playing with cache mechanisms of .NET yet, it's something on my list.
Kind regards,
Pawel Krakowiak
|
|
|
|
|
.Net is rather nice and makes it fairly easy for you. I found this article when I googled for the MSDN pages for Context.Cache, and it seemed easier to read anyway:
http://www.developer.com/net/net/article.php/1477771[^]
The guy does it a bit oddly though, giving a server too busy when it can't find the cached item (I'd go for a GetQuotes method myself that checks and updates the cache). HTH
|
|
|
|
|
I'd would like some suggestions on how to implement the actual bands, or groupings, editor GUI for a file export system I am busy with. Currently, I have a tree view on the left, explorer style, which lists as top level nodes all the Sections in an export, e.g. Customers, Clients, Customer Invoices etc. Then, under each section I have the data source queries for that section, and all record defintions, i.e. column collections, for that section.
Now in the XML definition file, under the record definitions, I have groupings to one level, where each grouping may be on Invoice Number. Each grouping can have a header, emitted once before each group, body emitted for each item in the group, and a footer, emitted once after each group. Header, body, and footer can contain one or more lines that correspond to record definitions. I'm now looking for ideas on how to present the layout of these groupings to users for editing.
|
|
|
|
|
Hi everybody,
I have 8+ years experience both in Java and .Net. Currently working a Software Engineer. I am getting opportunities for .NET architect position. But I am not aware of what kind of skill set required for this position so that I can upgrade my skills.
I will be thankful, for your suggestion and information.
Intelligence is measured by common sense not by how many scholarly books you read.
|
|
|
|
|
M LN Rao wrote: .NET architect position. But I am not aware of what kind of skill set required for this position
Probably the most important is Buzzwords. Seriously, if they don't provide a definition for architect it could mean just about anything.
|
|
|
|
|
Generally speaking an architect needs to be familiar with the most common ways to design information systems. On the "system" level, that means knowing the differences between desktop apps, client-server systems (including web applications), and distributed systems. On the application level it means defining the tiers and choosing the appropriate paradigm (e.g. service oriented or object oriented). It may also mean selecting technology - the term ".NET architect" is a bit odd imo, as one should normally choose a technology based on the desired architecture rather than the other way around. Nowadays an important consideration nearly everywhere is "interoperability", the ability to integrate with other systems, and I'd recommend that you study WCF if you don't already know it, as it is a very useful technology and easy to use with .NET.
|
|
|
|
|
I saw in many CRM products allowing there customers to add Fields at implementation level
Example: Customer of CRM Product can add “Phone2 “ as an extra field in to Registration form
Can any buddy tell me how this type of Architecture design will work?
|
|
|
|
|
|