Unhandled Exceptions

18 Aug

Summer of NHibernate Session 09: Effective Model-Driven Schemas is now available

The next installment of the Summer of NHibernate Screencast series is now available for general download!

In this session we explore the NHibernate SchemaExport class and start to exercise its ability to generate our database schema directly from our hbm.xml mapping files.  In addition, we touch briefly on some of the relative advantages of DDD (Domain Driven Design) and start to understand how this aspect of NHibernate can help us avoid having to place the database front-and-center in our development mind as we are refining our Domain Model in our overall software development process.

Some of the highlights from this session include:

  • Overview of the SchemaExport class and its role in our development process
  • Understanding the somewhat awkward API methods exposed by the SchemaExport class
  • Interpreting the somewhat arcane arguments to methods of the SchemaExport class
  • Controlling the names of foreign keys in our generated schema
  • Understanding the limitations of the DROP capabilities exposed by the SchemaExport class
  • ‘Tricking’ the SchemaExport class into creating VIEWs from our mapping files instead of TABLEs
  • defining a database INDEX in our mapping files
  • applying unique constraints to the database from our mapping files

As usual, comments, suggestions, feedback and constructive criticism are appreciated~! smile_wink

22 Responses to “Summer of NHibernate Session 09: Effective Model-Driven Schemas is now available”

  1. 1
    Nisar Khan Says:

    i was waiting for the video… i’m still downloaidng :)
    thanks Steve

  2. 2
    Nisar Khan Says:

    Steve,

    i’m wondering what are the choice in term retriving my data after i do SchemaExport (drop the database and recreate it again).?

    i’m on the half of screen cast, thought to ask you.

    thanks again.

  3. 3
    Nisar Khan Says:

    Steve,

    fyi: you can delete all your tables/views at one shot, just do SHIFT + object and hit the delete

    i see that you are deleting every single object one at a time… thought to share with you.

    thanks.

  4. 4
    sbohlen Says:

    @Nisar:

    Are you suggesting that SHIFT + DEL in sql mgt studio will drop the table even if there are FK dependencies on it? That’s why I was doing that in the order you saw in the screencast (to avoid the “sorry, you cannot drop table xyz because it will violate FK contraints…” message).

    Can you advise? If this is true, its certainly news to me (but also a very useful technique).

  5. 5
    Lookman Says:

    Hi steve,
    In your previous screen cast, you have a many to many relationship on the OrderProduct Table and you created a mapping file without a class. My question is how do you insert into the mapping table.

    thanks

  6. 6
    sbohlen Says:

    @Lookman:

    In the case of a m:n mapping table where the intermedial mapping table contains ONLY the pair of foreign key values (as is the case in this very simple model), there is no need to explicitly perform any CRUD operations against the actual ‘mapping’ table. This is one of the ‘geniuses’ of NHibernate — its capable of inferring what you need it to do from the mapping files that describe both ends of the relationship as being m:n.

    If you find that you need to store additional info in the intermediate mapping table (OrderProduct in the case of this model) other than just a pair of FK values then you actually DO have to define a class (an ‘entity’) that relates to that entry in the mapping table. In this case, you would define a pair of 1:m relationships to the entry in the mapping table rather than a m:n relationship that simply traverses THROUGH the intermediate table.

    An obvious example of this kind of need would be something that I’m actually planning to do in an uncoming session: add a ‘quantity’ field to the OrderProduct table to represent how many of each Product item is in each Order for each Customer. As soon as this change is made, this whole 3-table relation becomes a set of EXPLICIT 1:m relations rather than a m:n relation with IMPLICIT 1:m relations.

    Does this help…?

  7. 7
    Nisar Khan Says:

    @Steve,

    i did not realize that other tbls have FK sorry about that …my bad…. but one thing is that if your tbls having no FK then you can delete all at on shot by doing like this: click on the TABLE and on the right hand side you will see a SUMMARY window where you can select multiple objects and delete hit delete button … oh this technique you can apply for views/SP also.

    please see my question #2

    thanks

  8. 8
    Lookman Says:

    I do understand this for 1:m relationship,

    Parent p = session.Load(typeof(Parent),parentid);
    Child c = new Child();
    c.parent = p;
    p.Children.Add(c);

    but in case as an example am adding both order and product at the same time mapping the id to the foreign key in the database mapping table.

    you said:there is no need to explicitly perform any CRUD operations against the actual ‘mapping’ table.
    at what point does create the mapping and how, i don’t get it.

    thanks

  9. 9
    sbohlen Says:

    @Nisar:

    No issue; that’s sort of what I thought re: the FK issues in SSMS.

    Re: retrieving your data after the schema DROP, there really isn’t a good recommendation in this regard. DROP is (of course) a destructive operation and so running it will lose your data as well as your schema elements (tables, views, etc.).

    In the case of a developer working with unit tests (as is the case here), this doesn’t matter since the testdata.xml file contains our persisted test data that the DatabaseUnitTestBase class’ methods will simply reload into the database when it comes time to run the actual unit tests against the DB.

    In a real-world (production) situation with data you cared about you would (of course) never do what’s demonstrated here but for the support of the unit testing/development process its fine to just reload the data from the testdata.xml file that’s available in the code downloads for the session(s) since this is the data that the unit tests are ulitmately based upon.

  10. 10
    Nisar Khan Says:

    Steve,

    what is your take on “Database-Driven Modeling” vs “Model-Driven Schemas” which one you preference?

    thanks

  11. 11
    sbohlen Says:

    @Nisar:

    Snipped from an e-mail response I sent just last evening to another person who asked the same quesion…

    –snip–
    As for myself in this area, I tend to work in one of two ways (depending on the appropriate context):

    1) use code-gen to slave the DTO + mapping files to the DB; in this ‘mode’ I use partial classes and/or construct a higher-order domain model to manipulate the DTOs as needed and when I make a DB schema change I completely regen the DTO + mapping files again to keep them in-sync. This tends to work in cases where the DB schema is set by an outside force/external constraints or already exists

    2) hand-code the domain model and the mapping files and then use SchemaExport to push that to the DB initially; later I will make mods to both the domain + mapping files AND the db by hand to keep them in-sync (i.e., your suggestion of doing ShemaExport once). Later, if a significant refactor happens to the domain, I will consider re-running SchemaExport against the DB but I will often use a technique that actually ISN’T in the screencast: writing the DDL from SchemaExport to an external file (there is an override for the .Execute(…) method that takes a streamwriter object) and then clip out relevant parts of the captured DDL to paste into SSMS and then run ‘by hand’ after additional tweaking. Imperfect and error-prone (not easy to reproduce) but it works.
    –snip–

    Hope this helps and thanks for your continued feedback and interest~!

  12. 12
    sbohlen Says:

    @Lookman:

    Inspect the Order.hbm.xml and Product.hbm.xml mapping files in the code download. Both of those contain the mapping that supports this; inspect the mapping of the [bag]…[/bag] element in both mapping files (square-brackets used here b/c Wordpress will strip out xml-style angle brackets).

    Hope this helps.

    -Steve B.

  13. 13
    Ali Says:

    Hi Steve,
    thanks for the great screen casts.

    I just want to have some feedback regarding the column check.
    I did test the column check using NHibernate 2.0 (the latest release… just yesterday) and guess what it worked just fine and it indeed generated the desirable DDL.

    Cost REAL null check( Cost > 0) ,

    thanks
    Ali

  14. 14
    sbohlen Says:

    @Ali:

    Thanks for the update; nice to know that this is one of the 1.2 bugs fixed in 2.0~!.

  15. 15
    Marc Scheuner Says:

    Hi Steve, thanks for your ongoing great work! Truly enjoy every minute of your screen casts!

    Boy, this “work around” for dealing with views is pretty whacked - hasn’t anyone on the NHibernate team every thought of introducing something like a “table-type” property on the tag, with values of “table” or “view” ?? Having to let NHibernate create a “wrong” table, then whacking it out again and having to write a SQL statement (which needs to be kept up and adapted every time I add a new field!) seems more like an awful hack than anything…….

    C’mon - views ARE being used quite a bit in the database world - why can’t NHibernate support them in a better fashion? Has anything changed in the 2.0 code base in this regard?

  16. 16
    Mrunal Buch Says:

    Hi, Steve

    First of all a BIG thanks for these videos, they are wonderful and really informative (I started using some tools after watching you efficiently working in VS2008 !!!). Any ways…

    Having tried the SchemaExport class I am facing some problem. The Schemaexport class of mine somehow also creates a table called ProductOrder and fails with the following message.

    TestCase ‘M:DataAccessTest.NHibernateDataProviderTest.CreateDatebase’
    failed: There is already an object named ‘FK_ProductOrders’ in the database.
    Could not create constraint. See previous errors.
    NHibernate.HibernateException: There is already an object named ‘FK_ProductOrders’ in the database.
    Could not create constraint. See previous errors. —> System.Data.SqlClient.SqlException: There is already an object named ‘FK_ProductOrders’ in the database.
    Could not create constraint. See previous errors.
    at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
    at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
    at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
    at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
    at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async)
    at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe)
    at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
    at NHibernate.Tool.hbm2ddl.SchemaExport.Execute(Boolean script, Boolean export, Boolean format, Boolean throwOnError, TextWriter exportOutput, IDbCommand statement, String sql)
    at NHibernate.Tool.hbm2ddl.SchemaExport.Execute(Boolean script, Boolean export, Boolean justDrop, Boolean format, IDbConnection connection, TextWriter exportOutput)
    at NHibernate.Tool.hbm2ddl.SchemaExport.Execute(Boolean script, Boolean export, Boolean justDrop, Boolean format)
    — End of inner exception stack trace —
    at NHibernate.Tool.hbm2ddl.SchemaExport.Execute(Boolean script, Boolean export, Boolean justDrop, Boolean format)
    C:\Development\RnD\DineAndDiscussNHibernate_Session9\DataAccessTest\NHibernateDataProviderTest.cs(28,0): at DataAccessTest.NHibernateDataProviderTest.CreateDatebase()

    Am I missing something here ?

    Thanks

  17. 17
    Mrunal Buch Says:

    I am sorry I forgot to paste the entire script. Here is the full SQL Script output.

    ***************************************************************************

    Starting the MbUnit Test Execution
    Exploring DataAccessTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    MbUnit 2.4.2.130 Addin
    No tests found
    alter table ProductOrder drop constraint FK_ProductOrders
    alter table ProductOrder drop constraint FK_OrderProducts
    alter table [Order] drop constraint FK_CustomerOrders
    alter table viewCustomersWithYoyo drop constraint FKADD890B370C8035
    alter table viewCustomersWithYoyo drop constraint FKADD890B313C3E8FD
    alter table OrderProduct drop constraint FK_ProductOrders
    alter table OrderProduct drop constraint FK_OrderProducts
    if exists (select * from dbo.sysobjects where id = object_id(N’ProductOrder’) and OBJECTPROPERTY(id, N’IsUserTable’) = 1) drop table ProductOrder
    if exists (select * from dbo.sysobjects where id = object_id(N’Product’) and OBJECTPROPERTY(id, N’IsUserTable’) = 1) drop table Product
    if exists (select * from dbo.sysobjects where id = object_id(N’[Order]‘) and OBJECTPROPERTY(id, N’IsUserTable’) = 1) drop table [Order]
    if exists (select * from dbo.sysobjects where id = object_id(N’viewCustomersWithYoyo’) and OBJECTPROPERTY(id, N’IsUserTable’) = 1) drop table viewCustomersWithYoyo
    if exists (select * from dbo.sysobjects where id = object_id(N’Customer’) and OBJECTPROPERTY(id, N’IsUserTable’) = 1) drop table Customer
    if exists (select * from dbo.sysobjects where id = object_id(N’OrderProduct’) and OBJECTPROPERTY(id, N’IsUserTable’) = 1) drop table OrderProduct
    create table ProductOrder (
    Product INT not null,
    [Order] INT not null
    )
    create table Product (
    ProductId INT IDENTITY NOT NULL,
    Name NVARCHAR(50) not null,
    Cost REAL not null,
    primary key (ProductId)
    )
    create table [Order] (
    OrderId INT IDENTITY NOT NULL,
    OrderDate DATETIME not null,
    Customer INT not null,
    primary key (OrderId)
    )
    create table viewCustomersWithYoyo (
    CustomerId INT IDENTITY NOT NULL,
    Firstname NVARCHAR(255) null,
    Lastname NVARCHAR(255) null,
    OrderId INT null,
    OrderDate DATETIME null,
    primary key (CustomerId)
    )
    create table Customer (
    CustomerId INT IDENTITY NOT NULL,
    Version INT not null,
    Firstname NVARCHAR(50) null,
    Lastname NVARCHAR(50) null,
    primary key (CustomerId)
    )
    create table OrderProduct (
    [Order] INT not null,
    Product INT not null
    )
    alter table ProductOrder add constraint FK_ProductOrders foreign key (Product) references Product
    alter table ProductOrder add constraint FK_OrderProducts foreign key ([Order]) references [Order]
    alter table [Order] add constraint FK_CustomerOrders foreign key (Customer) references Customer
    alter table viewCustomersWithYoyo add constraint FKADD890B370C8035 foreign key (CustomerId) references Customer
    alter table viewCustomersWithYoyo add constraint FKADD890B313C3E8FD foreign key (OrderId) references [Order]
    alter table OrderProduct add constraint FK_ProductOrders foreign key (Product) references Product
    TestCase ‘M:DataAccessTest.NHibernateDataProviderTest.CreateDatebase’
    failed: There is already an object named ‘FK_ProductOrders’ in the database.
    Could not create constraint. See previous errors.
    NHibernate.HibernateException: There is already an object named ‘FK_ProductOrders’ in the database.
    Could not create constraint. See previous errors. —> System.Data.SqlClient.SqlException: There is already an object named ‘FK_ProductOrders’ in the database.
    Could not create constraint. See previous errors.
    at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
    at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
    at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
    at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
    at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async)
    at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe)
    at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
    at NHibernate.Tool.hbm2ddl.SchemaExport.Execute(Boolean script, Boolean export, Boolean format, Boolean throwOnError, TextWriter exportOutput, IDbCommand statement, String sql)
    at NHibernate.Tool.hbm2ddl.SchemaExport.Execute(Boolean script, Boolean export, Boolean justDrop, Boolean format, IDbConnection connection, TextWriter exportOutput)
    at NHibernate.Tool.hbm2ddl.SchemaExport.Execute(Boolean script, Boolean export, Boolean justDrop, Boolean format)
    — End of inner exception stack trace —
    at NHibernate.Tool.hbm2ddl.SchemaExport.Execute(Boolean script, Boolean export, Boolean justDrop, Boolean format)
    C:\Development\RnD\DineAndDiscussNHibernate_Session9\DataAccessTest\NHibernateDataProviderTest.cs(28,0): at DataAccessTest.NHibernateDataProviderTest.CreateDatebase()

    0 passed, 1 failed, 0 skipped, took 2.25 seconds.

    ***************************************************************************

    Thanks

  18. 18
    Mrunal Buch Says:

    Sorry Steve,

    My Bad….I had accidently written following in Product.hbm.xml

    ……

  19. 19
    sbohlen Says:

    @Marc:

    Yes, I agree this seems like a hack — and I will admit that its one that I arrived at all by myself after some fiddling so for all I know there may indeed be a better way (though I am unaware of it myself).

    To my knowledge, it doesn’t get any better in this area w/Nhib 2.0

  20. 20
    sbohlen Says:

    @Mrunal:

    Glad you got it solved~!

  21. 21
    Syed Says:

    I am trying to download the screen cast but this link always times out. Interestingly, I am able to download other sessions with .avi extension for example Session 06. Can anyone please guide me.

  22. 22
    Syed Says:

    I have managed to download it.

    Thanks
    Syed

Leave a Reply

© 2008 Unhandled Exceptions | Entries (RSS) and Comments (RSS)

GPS Reviews and news from GPS Gazettewordpress logo