What are the best practices in creating a data access layer for an object that has a reference to another object? - data-access-layer

(sorry for my English)
For example, in my DAL,I have an AuthorDB object, that has a Name
and a BookDB object, that has a Title and an IdAuthor.
Now, if I want to show all the books with their corresponding author's name, I have to get a collection of all the Books, and for each of them, with the IdAuthor attribute, find the Author's name. This makes a lot of queries to the database, and obviously, a simple JOIN could be used.
What are my options? Creating a 'custom' object that contains the author's name and the title of the book? If so, the maintenance could become awful.
So, what are the options?
Thank you!

Don't write something buggy, inefficient, and specialized ... when reliable, efficient, and generic tools are available. For free.
Pick an ORM. NHibernate, ActiveRecord, SubSonic, NPersist, LinqToEF, LinqToSQL, LLBLGenPro, DB4O, CSLA, etc.

You can create a View in the database that has the join built into it and bind an an object to that, e.g. AuthorBooksDB. It doesn't create too bad a maintenance headache since the view can hide any underlying changes and remains static.

If you can separate the database query from the object building, then you could create a query to get the data you need. Then pass that data to your builder and let it return your books.
With Linq to SQL, that can be done as easily as:
public IEnumerable<Book> AllBooks()
{
return from book in db.Books
join author in db.Authors on book.AuthorId equals author.Id
select new Book()
{
Title = book.Title,
Author = author.Name,
};
}
The same can be achieved with DataTables / DataSets:
public IEnumerable<Book> AllBooks()
{
DataTable booksAndAuthors = QueryAllBooksAndAuthors(); // encapsulates the sql query
foreach (DataRow row in booksAndAuthors.Rows)
{
Book book = new Book();
book.Title = row["Title"];
book.Author = row["AuthorName"];
yield return book;
}
}

Thank you very much for your inputs.
Actually, we are trying to keep the database objects as close as possible to the actual columns of the corresponding table in the database. That's why we cannot really add a (string) 'Author' attribute to the BookDB object.
Here is the problem I see with using 'View' objects. In the database, if the schema has to be modified for any reason (e.g: In the Book table, the 'Title' column has to be modified for 'The_Title', how do we easily know all the 'View' objects that have to be modified? In other words, how to I know what objects have to be modified when they make queries that use multiple joins?
Here, since we have a AuthorsBooks object, we can see by the name that it probably makes a query to the book and author tables. However, with objects that make 4 or 5 joins between tables we cannot rely on the object name.
Any ideas? (Thank you again, this is a great site!)

I suggest you take a look at Domain Driven Design. In DDD, you get all business objects from a repository. The repository hides your data store and implementation, and will solve your problems on how to query data and keeping track of database changes. Because every business object is retrieved from the repository, the repository will be your single point of change. The repository can then query your database in any way you find efficient, and then build your domain objects from that data:
var books = new BookRepository().GetAllBooks();
You should be able to code the repositories with any of the technologies mentioned by Justice.

Related

How to save an object with a list as attribute in a SQL Database

I want to store a list of Day objects in my sqflite database.
The Day class looks like this:
class Day {
String date;
List<DoneTask> doneTasks;
double score = 0;
Day({this.doneTasks, this.date});
}
the DoneTask class:
class DoneTask {
Category category;
double score;
String description;
DoneTask({this.category, this.score, this.description});
}
Category has an attribute id, which is all I want to store from that.
I'm not sure how I can realize that with sqflite.
I was thinking about adding the Attribute String day to the DoneTasks class for loading the DoneTasks in first, and sort them into the Days later. But this does not sound like a good solution for me, has anyone an idea how I could do it in a better way?
I'm very new to using SQL, so id appreciate simple answers/
(this is what I used yet for sqflite: https://flutter.dev/docs/cookbook/persistence/sqlite)
I would recommend going with a noSQL database if that is the data architecture you are going for. Of course, I do not know the scope of your entire project thus it is possible that an SQL database is a better fit for some reason that is unknown to me. But given just what you have presented, a noSQL alternative to sqflite seems like a better option. This would allow records to be stored effectively as objects, allowing you to store objects within objects, rather than having to create a bunch of tables cross referencing one another. It just seems more intuitive to me to do it that way.
Here is how I would save it :
First create a table to save your Day object. Inside it you will save only the date and score properties.
The method Database().insert return a Future<int> which is the id of the newly created row so you can use it to save your DoneTask and link them to the Day.
Now, you can save each of your List<DoneTask> in another table with a column id_day as their identifier.
Here is a modelization of what it could look.

Coldfusion ORM relationship id list

I'm wondering if there is a simple way to get an ID list of all the target objects relating to a source object in a coldfusion component using ORM?
I can see that you can do a collection mapping for one-to-many relationships, but I am using many-to-many relationships. I don't want to have to get the array of objects and then loop over it to get each id.
Is there any built in function or property that could do this?
I think something like the code sample below is a little too heavy since it is getting the whole query and then getting a single column from it.
valuelist( EntityToQuery( object.getRelationalFields() ).id )
Sometimes it doesn't make sense to use ORM, and this is the time. Use the good old <cfquery> for this!
I think ORMExecuteQuery may work for you, something like this:
result = ORMExecuteQuery("select id from Model as m where m.parent.id = :id", {id = 123});
Actual clause format depends on the relationship definition.
In a result you'll have the array of model PKs.

Loading a entity IDs CSV column as hydrated entities in NHibernate

I have a number of database table that looks like this:
EntityId int : 1
Countries1: "1,2,3,4,5"
Countries2: "7,9,10,22"
I would like to have NHibernate load the Country entities identifed as 1,2,3,4,5,7,9 etc. whenever my EntityId is loaded.
The reason for this is that we want to avoid a proliferation of joins, as there are scores of these collections.
Does fetching the countries have to happen as the entity is loaded - it is acceptable that you run a query to fetch these? (You could amend your DAO to run the query after fetching the entity.) The reason I ask is that simply running a query compared to having custom code invoked when entities are loaded requires less "plumbing" and framework innards.
After fecthing your entity, and you have the Country1,Country2 lists, You can run a query like:
select c from Country c where c.id in (:Country1)
passing :Country1 as a named parameter. You culd also retrieve all rows for both sets of countries
select Entity e where e.id in (:Country1, :Country2)
I'm hoping the country1 & country2 strings can be used as they are, but I have a feeling this won't work. If so, you should convert the Strings to a collection of Integers and pass the collection as the query parameter.
EDIT: The "plumbing" to make this more transparent comes in the form of the IInterceptor interface. This allows you to plug in to how entities are loaded, saved, updated, flushed etc. Your entity will look something like this
class MyEntity
{
IList<Country> Country1;
IList<Country> Country2;
// with public getter/setters
String Country1IDs;
String Country2IDs;
// protected getter and setter for NHibernate
}
Although the domain object has two representations of the list - the actual entities, and the list of IDs, this is the same intrusion that you have when declaring a regular ID field in an entity. The collections (country1 and Country2) are not persisted in the mapping file.
With this in place, you provide an IInterceptor implementation that hooks the loading and saving. On loading, you fetch the value of the countryXID property an use to load the list of countries (as I described above.) On saving, you turn the IList of countries into an ID list, and save this value.
I couldn't find the documentation for IInterceptor, but there are many projects on the net using it. The interface is described in this article.
No you cannot, at least not with default functionality.
Considering that there is no SPLIT string function in SQL it would be hard for any ORM to detect the discreet integer values delimited by commas in a varchar column. If you somehow (custom sql func) overcame that obstacle, your best shot would be to use some kind of component/custom user type that would still make a smorgasbond of joins on the 'Country' table to fetch, in the end, a collection of country entities...
...but I'm not sure it can be done, and it would also mean writing from scratch the persistence mechanism as well.
As a side note, I must say that i don't understand the design decision; you denormalized the db and, well, since when joins are bad?
Also, the other given answer will solve your problem without re-designing your database, and without writing a lot of experimental plumbing code. However, it will not answer your question for hydration of the country entities
UPDATE:
on a second thought, you can cheat, at least for the select part.
You could make a VIEW the would split the values and display them as separate rows:
Entity-Country1 View:
EntityId Country
1 1
1 2
1 3
etc
Entity-Country2 View:
EntityId Country
1 7
1 9
1 10
etc
Then you can map the view

NHibernate: Lazyload single property

I have currently moved my blogengine over from Linq2Sql to NHIbernate.
I'm stuck at the following performance problem:
I got one table: 'Posts', that has Id, Title, PostContent, DateCreated collumns and so on.
The problem is that, when I'm creating the "Recent posts list", I don't want the whole PostContent.
In Linq2Sql you can set lazy loading on a single property, so it won't be part of the SQL query until you actually ask for the property.
I tried doing this with Fluent NHibernate, by doing this:
Map(x => x.PostContent).LazyLoad();
It didn't work out. Googling around, it seems that NHibernate doesn't support this, so my question is, how can I fix this?
Is it really not possible to lazy load my property without moving the content to a seperate table?
Thanks in advance!
Update: this capability is now available in the NHibernate trunk.
See details on Ayende's blog, where the sample is exactly the scenario you describe here.
Here is how you can achieve what you want (kind of lazy loading but not the same)
var posts = NHibernateSessionManager.Session.CreateQuery("Select p.Id as Id, p.Title as Title, p.DateCreated as DateCreated from Post p")
.SetResultTransformer(NHibernate.Transform.Transformers.AliasToBean(typeof(Post)))
.List<Post>();
What the AliasToBean is intended for is, doing selects for specific columns (usually from more than one entities) and return a strongly typed collection instead of a System.Object[].
Now if you Bean (class) is your Post class then it will popultate to that class ONLY the requested columns and nothing else.
What you will NOT be having though is a collection of NHibernate managed objects. All Posts in the returned lists are detached non controlled objects.
For doing things like "getting all recent posts" without having to get the most "heavyweight" columns of your entity while not having to create other classes to convert the data to, the above solution is kind of perfect.
Check this out for more info:
NHibernate: returning a strongly typed list having applied an aggregate function
This is not possible when PostContent is mapped to the same table, because the performance difference is not significant in 99% of the situations. When you are in the 1%, you can consider using handbuild sql instead of a orm for that case.
Lazy/Eager loading is not possible at all with linq to sql (out of the box) as far as I know.
What you can do create a different class with the data you want to select and just select that data into a new object.

nhibernate and DDD suggestion

I am fairly new to nHibernate and DDD, so please bear with me.
I have a requirement to create a new report from my SQL table. The report is read-only and will be bound to a GridView control in an ASP.NET application.
The report contains the following fields Style, Color, Size, LAQty, MTLQty, Status.
I have the entities for Style, Color and Size, which I use in other asp.net pages. I use them via repositories. I am not sure If should use the same entities for my report or not. If I use them, where I am supposed to map the Qty and Status fields?
If I should not use the same entities, should I create a new class for the report?
As said I am new to this and just trying to learn and code properly.
Thank you
For reports its usually easier to use plain values or special DTO's. Of course you can query for the entity that references all the information, but to put it into the list (eg. using databinding) it's handier to have a single class that contains all the values plain.
To get more specific solutions as the few bellow you need to tell us a little about your domain model. How does the class model look like?
generally, you have at least three options to get "plain" values form the database using NHibernate.
Write HQL that returns an array of values
For instance:
select e1.Style, e1.Color, e1.Size, e2.LAQty, e2.MTLQty
from entity1 inner join entity2
where (some condition)
the result will be a list of object[]. Every item in the list is a row, every item in the object[] is a column. This is quite like sql, but on a higher level (you describe the query on entity level) and is database independent.
Or you create a DTO (data transfer object) only to hold one row of the result:
select new ReportDto(e1.Style, e1.Color, e1.Size, e2.LAQty, e2.MTLQty)
from entity1 inner join entity2
where (some condition)
ReportDto need to implement a constructor that has all this arguments. The result is a list of ReportDto.
Or you use CriteriaAPI (recommended)
session.CreateCriteria(typeof(Entity1), "e1")
.CreateCriteria(typeof(Entity2), "e2")
.Add( /* some condition */ )
.Add(Projections.Property("e1.Style", "Style"))
.Add(Projections.Property("e1.Color", "Color"))
.Add(Projections.Property("e1.Size", "Size"))
.Add(Projections.Property("e2.LAQty", "LAQty"))
.Add(Projections.Property("e2.MTLQty", "MTLQty"))
.SetResultTransformer(AliasToBean(typeof(ReportDto)))
.List<ReportDto>();
The ReportDto needs to have a proeprty with the name of each alias "Style", "Color" etc. The output is a list of ReportDto.
I'm not schooled in DDD exactly, but I've always modeled my nouns as types and I'm surprised the report itself is an entity. DDD or not, I wouldn't do that, rather I'd have my reports reflect the results of a query, in which quantity is presumably count(*) or sum(lineItem.quantity) and status is also calculated (perhaps, in the page).
You haven't described your domain, but there is a clue on those column headings that you may be doing a pivot over the data to create LAQty, MTLQty which you'll find hard to do in nHibernate as its designed for OLTP and does not even do UNION last I checked. That said, there is nothing wrong with abusing HQL (Hibernate Query Language) for doing lightweight reporting, as long as you understand you are abusing it.
I see Stefan has done a grand job of describing the syntax for that, so I'll stop there :-)