Let's say we have a table in SQL represented in C# like this:
public class Product
{
public int ID { get; set; }
public string Name { get; set; }
public string Picture { get; set; } // filename of the picture, e.g. apple.jpg
public int CategoryID { get; set; }
}
Now we would query the database and retrieve the object, let's say with values like this:
ID = 1
Name = Yellow apple
Picture = apple.jpg
CategoryID = 25
All perfectly normal. The thing I'm meditating about at the moment is this: if I want to show a product, I need some additional info that wasn't queried from the database, like exact file path to the image, all we have is
apple.jpg
, but we need maybe something like
~/images/apple.jpg
So, I was thinking of 3 possibilities:
1.) add a new property to the class Product
public string PictureUrl
{
get
{
return "~/images/apple.jpg";
}
}
2.) specify the full url during performing of the presentation logic, let's say:
public void ShowProductDetails()
{
Product p = ProductRepo.GetProduct(id);
txtName.Text = p.Name;
imgPicture.ImageUrl = "~/images/" + p.Picture;
}
3.) use Decorator pattern
First approach seems wrong to me (even though I have been using it for quite a long time), because I'm trying to have a layered web application. I'm not sure hard-coding this is a good way to go.
Second approach is better, but worse in the sense it can't be easily reused. If I have multiple places where I'm doing the same thing and something changes, ... Maybe it would work if I specify some static constants holding the paths...
Third possibility seems quite complicated in terms of maintainability. The number of my classes would probably have to double. If I have 30 classes now, it would suddenly become 60 :/
What is the best/recommended way of doing things like this? If I add properties to my POCOs that aren't included in the db schema, I'm unable to use Dapper.Contrib or Rainbow and similar libraries, because even though "selects" work fine, I can't "insert" nor "delete". I have to hard-code the sql strings for every command which becomes really tedious after some time, when you're doing all the time the same stuff.
EDIT:
The solution from Govind KamalaPrakash Malviya is great, but can't be used every time. I need a way to solve this for any type of properties, even those more complex ones - for instance the number of photos of some album. It's a good idea to query the count of photos along with albums, but assign it to what? Create a decorated class using a Decorator pattern?
How do YOU solve this kind of architecture problems?
I think you should manipulate it in presentation layer because image path for presentation layer only. so use third one but make it easy using utility method
public class PathUtility
{
public static string ImageUrl(string imageName)
{
if(string.IsNullOrEmpty(imageName))
{
throw new Exception("Image name not valid!!");
}
else
{
return "YourImageDirectroyUrl" + imageName;
}
}
}
and use it easily
PathUtility.ImageUrl("apple.jpg");
I normally solve this by leaving the entity object as it is and creating an extra data container, which will either hold a reference to the corresponding entity or implement the corresponding properties from the entity object itself. In the latter case I use a mapping library (AutoMapper) to copy data from an entity to a the enhanced container.
The logic for filling the extra properties normally lies in a factory (or factory method). It's up to you, where you want to place this in your architecture. In a current project we are including them in our data access facade on client side, because we don't want to clutter the data access layer with too many DTO's. This of course means, that the data access layer still needs to support retrieving the extra properties. In your case an operation like int GetNumberOfPhotosForAlbum(Album album).
We found that the benefits outweigh the risk of an ever-growing contract of the data access layer, which of course might need to support many different calls like the example above instead of just EnhancedAlbum GetEnhancedAlbumWithAllKindsOfExtraProperties(long albumId). This might also become a performance problem in some scenarios, because of the overhead of an increased frequency of service calls. In the end you need to decide, what's best for your project.
I like this approach, because my entities (Album) stay untouched and I retain a clear separation of concerns between persistence, client logic and mapping.
Example:
class Album
{
string Name { get; set; }
}
class EnhancedAlbum
{
Album Album { get; set; }
int NumberOfPhotos { get; set; }
}
class EnhancedAlbumFactory
{
private MyDataService _dataService;
//include some means of constructing or (better) injecting the data service
EnhancedAlbum GetEnhancedAlbum(Album album)
{
return new EnhancedAlbum
{
Album = Album,
NumberOfPhotos = _dataService.GetNumberOfPhotosForAlbum(album);
};
}
}
Related
I want to extend the documents that I receive from a SELECT clause.
Lets assume a I have a collection that stores documents in the following shape
{"foo": "yeah I am a foo", "bar": "And I am a bar"}
so that the query
SELECT * FROM f
would return the above document(s)
Now I want to add an additional property that is NOT part of the documents stored as part of the projection of the SELECT statement.
Basically I'd like to do something like using Javascript's spread operator (which is not possible in Cosmos DB)
SELECT {...*, "newprop": "oh! I am new here!"} FROM f
and which should then return document(s) like this
{"foo": "yeah I am a foo", "bar": "And I am a bar", "newprop": "oh! I am new here!"}
The one thing I DONT WANT TO DO is to repeat all the toplevel properties of my documents. So a solution in the form of
SELECT {"foo": f.foo, "bar":f.bar, "newprop": "oh! I am new here!"} FROM f
is not desired.
I also tried to get that done via a function. Which I was not able to do as I cant find out how to get the toplevel object / document handle within the SELECT clause.
I tried the following
SELECT udf.ExtendDocument(*) FROM f
SELECT udf.ExtendDocument($1) FROM f
SELECT udf.ExtendDocument(f) FROM f
SELECT udf.ExtendDocument(value) FROM f
most of which produced a syntax error
It's not possible to use SELECT *, then append columns to the projection.
One option you could explore is to add a static property and value to the class that you deserialize your data into.
For instance, you could create a class like this simple one for a person with a hardcoded property and default value. Then deserialize your query results into it with the static value added as another property with a default value.
class Person
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "pk")]
public string Pk { get; set; }
[JsonProperty(PropertyName = "firstName")]
public string FirstName { get; set; }
[JsonProperty(PropertyName = "lastName")]
public string LastName { get; set; }
public string MyStaticColumn get; set; } = "Default Value";
}
Then the code to run the query...
public static async Task QueryPerson(Container container)
{
QueryDefinition query = new QueryDefinition("select * from c");
FeedIterator<Person> resultSet = container.GetItemQueryIterator<Person>(
query, requestOptions: new QueryRequestOptions()
{
MaxConcurrency = -1
});
List<Person> results = new List<Person>();
while (resultSet.HasMoreResults)
{
FeedResponse<Person> response = await resultSet.ReadNextAsync();
foreach(var p in response)
{
results.Add(p);
}
}
}
So I found a solution.
A) Build a user defined function that does the "Extension"
function extendProjection(x) {
var result = {
//usually one want to extend the returned doc
//with some new calculated properties and not
//with a static value
newprop: calculateNewPropFromObject(x)
}
return Object.assign(result, x)
}
B) Use the user defined function in your SELECT
SELECT VALUE udf.extendProjection(c) FROM c
//it is important to use the keyword "VALUE" eitherwise
//the resulting doc will look {$1: { //the extendedprojection }}
Having described that I would recommend against this approach
Your RUs will easily tripple. The reason seems to be the usage of the JS itself and not so much what the JS engine does.
its not possible to "reuse" different registered UDFs within your JS code.
So one has to copy code snippets
"Extended Properties" are not useable in your WHERE clause
Runtime error messages returned from Cosmos DB are horrible to decipher.
The lack of any decent development environment is basically a no go.
Like #mark-brown already answered, it does not seem to be possible.
I would just like to add that likely you shouldn't do that anyway and offer a workaround arguably better than the UDF (which is costly, hard-to-maintain, does not support multiple concurrent logic versions, etc).
If you want to add extra calculations to query output based on the same entire document, then it would make more sense to do it in business layer (after querying), not data layer (CosmsosDB queries). It would also be faster (less calculations, less data to move) and cheaper (less RU).
If you want to add static data (ex: a fix string or other constants), then the same argument applies - passing it back-and-forth to cosmosDB just makes things slower and costlier. That's not the responsibility of storage.
The workaround
If the goal is to query an entire CHILD object and add only a few selected properties from other areas of documents then its best not to try to flatten the object. Just keep your storage model objects and extras side-by-side, ex:
select c.childWithAllTheFutureChildren,
c.other.location.single.value as newProp
from c
If you really-really want to add some calculation/statics to query output then you could also still use the same pattern for entire document:
SELECT c as TheRealStoredThing,
'oh! I am new here!' as theNewProp
FROM c
Yes, it does require you to have a separate model on client side for this query, but that's a good clean practice anyway. And it's much simpler than using/maintaining UDFs.
A domain model that does not contain the business logic for the model is considered an anti-pattern by some -
https://en.wikipedia.org/wiki/Anemic_domain_model
But in some applications, such as .NET applications, seem to prefer a model with out business logic.
Would the following be a good implementation of combining these two concepts.
Have a base model, with the constructor and all "set" statements defined as protected, then have a class that inherits from that base class, which implements the business logic for the base class and helps create the base object. The base model could then be used for something like an MVC View.
Base class -
public class Customer
{
protected Customer()
{
}
public string FirstName { get; protected set; }
public string LastName { get; protected set; }
public int Age { get; protected set; }
}
Inheriting class -
public class CustomerCreator : Customer
{
public void SetFirstName(string firstName)
{
this.FirstName = firstName;
}
public void SetLastName(string lastName)
{
this.LastName = lastName;
}
public string SetAge(int age)
{
string result = "";
if (age < 18)
{
return "can't be less than 18";
}
this.Age = age;
return result;
}
public Customer GetCustomer()
{
return this;
}
}
Are there any potential hazards to this pattern?
Is this a pattern that is already commonly used?
I don't think you're really buying yourself anything here. Ultimately casting to Customer via the GetCustomer() method doesn't actually change anything in terms of the ability to get properties on the model. You're still indirectly robbing your customer of its own business logic with the derived CustomerCreator class. I think you're better off placing your logic in the class you expect to work with (ie Customer) and creating a projection in the form of a viewmodel or DTO for displaying data to the client. Try something like this for your domain model:
public class Customer
{
private int _age;
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age
{
get => _age;
set
{
if (value < 18)
{
throw new ArgumentOutOfRangeException(nameof(Age), "can't be less than 18");
}
_age = value;
}
}
protected Customer() { }
}
A couple of additional points:
I'd recommend avoiding restricting access on your properties unnecessarily. In the case of FirstName and LastName there are no invariants attached to them so the protected setters are not only confusing, but require additional unnecessary indirection to work with. This could also be confusing in the future if other devs (or you after some time away to forget) question why the accessibility was limited to begin with. Going from less to more restricted access modifiers can be done when business rules demand it and it's a relatively safe operation- almost all issues that can arise as a result of restricting access will do so at design time. Going from more restrictive to less restrictive access should always be done with an abundance of caution- if a property/field/method/etc is less than public then hopefully it was designed that way with good reason. Overlooking those reasons can lead the circumvention of invariants, which can lead to runtime issues, inconsistent system state, and corrupt data.
There is nothing particular to C#/.NET that requires or recommends anemic models. Many developers write their models that way and then act upon them with a variety of services, but that general pattern is not necessary by any means nor is it specific to C#. The teams I have worked with implement rich models that are directly persisted and rehydrated via ORMs such as Entity Framework and while it sometimes requires making concessions due the the quirks of a particular ORM, it always ends up working well.
What you're describing is a builder pattern a pattern that's a part of a more broadly defined set of creational patterns. The most obvious examples are builders such as StringBuilder and UriBuilder.
There's a few problems with a builder pattern on the entity side of things in the DDD world, and in particular your current implementation.
First, builders are suitable for value objects, which are fungible and can have value even if not complete (e.g. just a street address with no zip code). For entities, a factory would be more suitable because we want our entities to always be valid (see this great blog entry by Vladimir Khorikov). A factory doesn't turn out an incomplete car, for example; no one would buy that car because, well, it's not a car yet!
Second, your example uses inheritance, and mixes concepts. Let's examine this.
(Wrong) Alternatives
Inheritance models an is-a relationship. Ask yourself, "Is a CustomerBuilder a Customer?" The answer is no; you can say a HouseBuilder (a person) is not a House so inheritance is not appropriate here. It's the same with customers.
You're also not going to do this using composition, which models a has-a relationship. Does a CustomerBuilder have a Customer? No. By analogy, a HouseBuilder does not have a house, a house builder makes a house. Aside: the builder might live in a house, and thus own one, but how does that have anything to do with building some other house?
Creational Patterns
So, the most natural relationship here is a creational one, and in particular a factory. In your case you'd want a customer factory that creates a customer. It accepts all the inputs such as name, age, and so on, and when finally ready to create the customer, it constructs the customer all at once, completely and correctly. If the final customer is not meant to have things like name or age changes, these properties could be made get-only.
What's important here, is that if you extend customer with a builder as you were doing, you could allow that customer to be changed incorrectly; this is antithetical to DDD. Worse, you've got the confusion between the thing being built and the thing doing the building.
Refinements
Ok, so what if your domain allows a customer to age or their name to change? You don't want unfettered write access to these properties. Consider this example: John Doe is 21 years old. Some piece of calling code sets the first name to Mike and then the age to 30 one year later! Makes no sense. Not only is your entity anemic (no internal logic), the logic is external to your domain and allows for time travel!
Let's instead make your Customer less anemic, and provide sensible rules or policies:
public class Customer
{
public Customer(string firstName, string lastName, int age)
{
...
}
public string FirstName { get; private set; }
public string LastName { get; private set; }
public int Age { get; private set; }
public void AgeByOneYear()
=> Age += 1;
public void ChangeFirstName(string newName, IRenamingPolicy renamingPolicy)
=> FirstName = renamingPolicy.ValidateName(newName);
...
}
Relationship of the Factory/Builder to the Domain
In DDD, factories are part of the domain, but not the domain model itself. At this point you may ask, "Well, wait. This factory has domain logic in it, shouldn't that be in the domain model?"
Good question. The answer is yes, and this will make your domain model less anemic. Another aside: you can have entities in your domain model that don't have much (if any) internal logic without your model being considered anemic. As long as the business/domain logic is in your DDD model, and not in your orchestration, persistence, or other layers, you can skate by the anemic label. This is what I did by externalizing renaming logic in a policy, but effecting the renaming action in the Customer. The RenamingPolicy contains domain logic and is part of your domain.
Final Thoughts
Anemic models (or not) and creational patterns are orthogonal concepts, but I've shown how thinking of them together can lead to a coherent domain model.
Using a Customer entity (even if it was a base class of some kind) is probably not a good idea to use as an MVC view or view model. The needs are different; an entity has behavior in a domain whereas a view model is anemic and expresses properties that are bound to a view for presentation.
If your experience is that .NET domain models are anemic, I'd say that's anecdotal and shouldn't set precedent. For simple apps, that's fine; for rich enterprise apps, you might be looking at a bad design.
A model is anemic if you are using it to just store/carry data and keeping business logic related to it in some other place.
In your example you are inheriting a class purely to create Customer object in a specific way but it's not really protecting any in-variance other than supporting a style of writing code. While I refrain to say something is wrong because there might be a reason behind it, I fail to see a valid one here.
Two main purpose of a language supporting inheritance, in my opinion/understanding are:
Code reuse
Encapsulation - indirect
If you really want to protect how a Customer Object can be instantiated, you could have a static factory method on the Customer class itself. However that doesn't make that model 'rich'.
Difference between 'rich' and 'anemic' is where you decide to keep the business logic - outside of your domain entities (aggregates to be precise but will go with entity for simplicity) or as an operation on domain entities.
If you consider your system as a series of coordinated state changes of entities, you have a choice where you keep the logic of that state change. In rich model you include it as an operation on the entity itself so you have tighter control maintaining the invariant.
I'm using Entity Framework (DB First) on a new project and wanted to add some customisation to the classes generated. However, my changes are obviously lost every time that the edmx is refreshed. I was just wondering if there is a design pattern for handling this sort of thing?
As an example, suppose I have a class with a integer property; StatusID - and I'd like to extend the entity class so that the status value can also be accessed/set via the related enum and finally a property that gets a text representation of that Enum from the description attribute. This all works, but those customisations are lost when the model is refreshed. I appreciate that the property can be converted to an enum, so the latter property that gets the description of the enum is perhaps a better example for this question.
I think I know the answer but I just wanted to put this out there in case there were some magic tricks that would allow this to work and prevent those customisations from being lost.
public int StatusID { get; set; }
public Enumerations.ValidationStatus StatusEnum
{
get
{
return (Enumerations.ValidationStatus)StatusID;
}
set
{
StatusID = (int)value;
}
}
public string StatusText
{
get
{
return MyMethodThatGetsTheEnumDescription(StatusEnum);
}
}
Two Solutions to work around the problem:
User Data Transfer Object(DTO) nd put the enum there. then use Automapper or manually map between the DB Model and the DTO Model (best practice)
Instead of enum you can use extension functions on the model and define your getter, setters and any extra properties you want as extension functions to the class
(will add some complexity to your models)
I have a web solution (in VS2010) with two sub-projects:
Domain which holds the Model classes (mapped to database tables via Entity Framework) and Services which (besides other stuff) are responsible for CRUD operations
WebUI which references the Domain project
For the first pages I've created I have used the Model classes from the Domain project directly as Model in my strongly typed Views because the classes were small and I wanted to display and modify all properties.
Now I have a page which should only work with a small part of all properties of the corresponding Domain Model. I retrieve those properties by using a projection of the query result in my Service class. But I need to project into a type - and here come my questions about the solutions I can think of:
I introduce ViewModels which live in the WebUI project and expose IQueryables and the EF data context from the service to the WebUI project. Then I could directly project into those ViewModels.
If I don't want to expose IQueryables and the EF data context I put the ViewModel classes in the Domain project, then I can return the ViewModels directly as result of the queries and projections from the Service classes.
In addition to the ViewModels in the WebUI project I introduce Data transfer objects which move the data from the queries in the Service classes to the ViewModels.
Solution 1 and 2 look like the same amount of work and I am inclined to prefer solution 2 to keep all the database concerns in a separate project. But somehow it sounds wrong to have View-Models in the Domain project.
Solution 3 sounds like a lot more work since I have more classes to create and to care about the Model-DTO-ViewModel mapping. I also don't understand what would be the difference between the DTOs and the ViewModels. Aren't the ViewModels exactly the collection of the selected properties of my Model class which I want to display? Wouldn't they contain the same members as the DTOs? Why would I want to differentiate between ViewModels and DTO?
Which of these three solutions is preferable and what are the benefits and downsides? Are there other options?
Thank you for feedback in advance!
Edit (because I had perhaps a too long wall of text and have been asked for code)
Example: I have a Customer Entity ...
public class Customer
{
public int ID { get; set; }
public string Name { get; set; }
public City { get; set; }
// ... and many more properties
}
... and want to create a View which only shows (and perhaps allows to edit) the Name of customers in a list. In a Service class I extract the data I need for the View via a projection:
public class CustomerService
{
public List<SomeClass1> GetCustomerNameList()
{
using (var dbContext = new MyDbContext())
{
return dbContext.Customers
.Select(c => new SomeClass1
{
ID = c.ID,
Name = c.Name
})
.ToList();
}
}
}
Then there is a CustomerController with an action method. How should this look like?
Either this way (a) ...
public ActionResult Index()
{
List<SomeClass1> list = _service.GetCustomerNameList();
return View(list);
}
... or better this way (b):
public ActionResult Index()
{
List<SomeClass1> list = _service.GetCustomerNameList();
List<SomeClass2> newList = CreateNewList(list);
return View(newList);
}
With respect to option 3 above I'd say: SomeClass1 (lives in Domain project) is a DTO and SomeClass2 (lives in WebUI project) is a ViewModel.
I am wondering if it ever makes sense to distinguish the two classes. Why wouldn't I always choose option (a) for the controller action (because it's easier)? Are there reasons to introduce the ViewModel (SomeClass2) in addition to the DTO (SomeClass1)?
I would solve your problem by using an auto-mapping tool (like AutoMapper) to do the mapping for you. In cases where the mapping is easy (for example if all properties from one class should be mapped to properties with the same name on another class) AutoMapper will be able to do all the hook-up work for you, and you'll have to give a couple of lines of code to note that there should be a map between the two at all.
That way, you can have your entities in Domain, and a couple of view model classes in your WebUI, and somewhere (preferrably in WebUI or a sub namespace of the same) define maps between them. Your view models will in effect be DTOs, but you won't have to worry much about the conversion process between the domain and your DTO classes.
Note: I would strongly recommend against giving your Domain entities straight to the views of your MVC web UI. You don't want EF to "stick around" all the way to the front-end layer, in case you later want to use something other than EF.
introduce ViewModels which live in the
WebUI project and expose IQueryables
and the EF data context from the
service to the WebUI project. Then I
could directly project into those
ViewModels.
The trouble with this is you soon run into problems using EF trying to 'flatten' models. I encountered something similar when I had a CommentViewModel class that looked like this:
public class CommentViewModel
{
public string Content { get; set; }
public string DateCreated { get; set; }
}
The following EF4 query projection to the CommentViewModel wouldn't work as the couldn't translate the ToString() method into SQL:
var comments = from c in DbSet where c.PostId == postId
select new CommentViewModel()
{
Content = c.Content,
DateCreated = c.DateCreated.ToShortTimeString()
};
Using something like Automapper is a good choice, especially if you have a lot of conversions to make. However, you can also create your own converters that basically convert your domain model to your view model. In my case I created my own extension methods to convert my Comment domain model to my CommentViewModel like this:
public static class ViewModelConverters
{
public static CommentViewModel ToCommentViewModel(this Comment comment)
{
return new CommentViewModel()
{
Content = comment.Content,
DateCreated = comment.DateCreated.ToShortDateString()
};
}
public static IEnumerable<CommentViewModel> ToCommentViewModelList(this IEnumerable<Comment> comments)
{
List<CommentViewModel> commentModels = new List<CommentViewModel>(comments.Count());
foreach (var c in comments)
{
commentModels.Add(c.ToCommentViewModel());
}
return commentModels;
}
}
Basically what I do is perform a standard EF query to bring back a domain model and then use the extension methods to convert the results to a view model. For example, the following methods illustrate the usage:
public Comment GetComment(int commentId)
{
return CommentRepository.GetById(commentId);
}
public CommentViewModel GetCommentViewModel(int commentId)
{
return CommentRepository.GetById(commentId).ToCommentViewModel();
}
public IEnumerable<Comment> GetCommentsForPost(int postId)
{
return CommentRepository.GetCommentsForPost(postId);
}
public IEnumerable<CommentViewModel> GetCommentViewModelsForPost(int postId)
{
return CommentRepository.GetCommentsForPost(postId).ToCommentViewModelList();
}
Talking about Models, ViewModels and DTOs is confusing, personally I don't like to use these terms. I prefer to talk about Domain Entities, Domain Services, Operation Input/Result (aka DTOs). All of these types live in the Domain layer. Operations is the behavior of Entities and Services. Unless you are building a pure CRUD application the presentation layer only deals with Input/Result types, not Entities. You don't need additional ViewModel types, these are the ViewModels (in other words, the Model of the View). The View is there to translate the Operation Results to HTML, but the same Result could be serialized as XML or JSON. What you use as ViewModel is part of the domain, not the presentation layer.
I want to try custom code, this is for my uni project. What if I have Tables - UserCar, CarMake, and CarModel.
UserCar - userId, carId, carMakeId, CarModelId
CarMake - CarMakeId, MakeName
CarModel - CarModelId, ModelName
So I want to display on the page User car, using 3 layer architecture. So how do I map this tables??? to business object or objects??? Could you help me please?
Well, you mention 3-layer architecture, so I guess you're looking at a Data/Application/Presentation approach. Of course, in order for that to make sense you may need to provide more than the brief details you gave in your question.
For instance, when we talk about the Application tier, it really makes sense to have one if you have "Appalication logic". With your brief info there isn't really application logic other than displaying your data to screen. See this wikipedia entry for more info on the topic of Multitier (or n-tier) architecture (and 3-tiers as a subset) in general.
That being said, if you have your 3 tables in a data storage of sort (such as a database), we can quickly make a 3-tiers app like this.
1~ Data Tier:
Create classes that match the storage tables, such as (using C# syntax):
public class DT_UserCar
{
public string userId;
public string carId;
public string carMakeId;
public string CarModelId;
}
I'm using the DT_ prefix to indicate this class belongs to the Data Tier.
In addition, you need to have some code to let instance of these classes be read from the storage and probably be saved to storage. Of course you have options already. You could create a separate class that knows how to do all that, like
public class Storage
{
public DT_UserCar ReadUserCar(string carId) { /* implementation */ }
public DT_CarMake ReadCarMake(string carmakeId) { /* implementation */ }
/* and so on... */
}
Or you could decide that each class should know how to serialize/deserialize itself to/from the storage, and go with:
public class DT_UserCar
{
public string userId;
public string carId;
public string carMakeId;
public string CarModelId;
public static DT_UserCar Read(string carId) { /* implementation */ }
public void Write() { /* implementation */ }
}
A third, and much better alternative (for bigger projects) is to find a third-party tool that takes care of all of this for you. After all, given the storage structure (e.g.: the database schema) all of this code can be automated... I won't go into details here since you can find a lot of information about this sort of tools (ORM tools) and their characteristics, but mostly because it doesn't seem ot be part of your exercise.
2~ Application Tier:
As I said, your use case doesn't seem to include a lot of 'business logic'. However, you do mention that the data from those 3 storage tables should be merged somehow, so I'll take that as your one piece of business logic. Hence, we should create a business class (or business entity, or Domain Entity, or Domain model, whichever term you feel like using, they all have different connotations but a lot in common) like this:
public class AT_UserCar
{
public DT_UserCar _userCar;
public DT_CarMake _carMake;
public DT_CarModel _carModel;
public AT_UserCar(DT_UserCar userCar, DT_CarMake carMake, DT_CarModel carModel)
{
_userCar = userCar;
_carMake = carMake;
_carModel = carModel;
}
}
I'm using the AT_ prefix to indicate this class belongs to the Application Tier. Note that I would rather have those 3 as private properties, but for the sake of brevity I'm relaxing other guidelines in this sample code.
Now, as we read an instance of this class form the storage, we'll have to merge the proper DT_ objects in it. Again, you can have this code in the same class AT_UserCar, or decide to split it out into some separate class like this one:
public class AT_UserCarReader
{
public AT_UserCar Read(string userCarId, string carMakeId, string carModelId)
{
DT_UserCar userCar = DT_UserCar.read(userCarId);
DT_CarMake carMake = DT_CarMake.Read(carMakeId);
DT_CarModel carModel = DT_Carmodel.read(carModelId);
return new AT_UserCar(userCar, carMake, carModel);
}
}
An equivalent AT_UserCarWriter class would do the inverse operation of receiving a single AT_UserCar object and writing to the data storage 3 separate objects extracted from it: a DT_UserCar, a DT_CarMake, and a DT_CarModel.
Note that most of this code can also be automated and there is a plethora of tools that will take care of it for you.
3~ Presentation Tier:
Finally, we get to display something on screen. The important thing here is to remember that your Presentation Tier should never deal directly with the Data Tier, but only with the Application Tier.
So, for instance, if I have to retrieve a UserCar by id and display it in a web page, I could write something like this
AT_UserCar car = AT_UserCarReader.Read(userCarId, carMakeId, carModelId);
tbox_userId = car._userCar.userId;
That's, of course, a very small example, but I hope the quick run-through can help you out.
The core of 3-tier architecture (and n-tier, in general) is to separate different concerns into different layers. If you look at the example above, we targeted 3 concerns:
talking to the data storage: we did this exclusively in the Data Tier;
dealing with application logic such as 'merging' data from different tables into a single logical unit: we did this exclusively in the Application Tier;
dealing with presenting to screen the data and -in more general terms- interacting with the user: we did this exclusively in the Presentation Tier.
HTH.
Map the tables to Data Access Objects and use those in your Business Layer. Each one of your DAO will have properties corresponding to each column in the respective table; use any ORM of your liking (such as NHibernate) and you are good to go.