3
\$\begingroup\$

Scenario: I need to insert a record in a database and use the id resulting from that operation for every other operation needed.

So I've created a class that contains all details of the object that needs to be persisted in the database and added an Id field to store the record id returned by the database operation.

public class MetadataObject {
    protected long Id { get; private set; }
    protected long RegistrationDate { get; private set; }
    protected long FileName { get; private set; }

    public MetadataObject(string fileName)
    {
        FileName = fileName;
        RegistrationDate = DateTime.Now;
    }
}

1) Once I create a MetadataObject, the Id property is 0 (not initialized). Then I make the call to the database.

metadata.Id = RegisterMetadataAndReturnId(metadata);

2) Another thing that I could do is to assign a value to the Id field immediately after I get it back from the database. The method that handles this would look like this

public void RegisterMetadata(MetadataObject metadata)
{
    long recordId;
    var metadataInsert = CreateStoredProcedure("RegisterMetadata");
    metadataInsert.Execute();

    [assign recordId with value received from stored procedure]

    metadata.Id = recordId;
}

Second version looks better in my opinion, the only doubt I have is if the method calling the stored procedure must make sure the metadata object Id property is set before exiting. Or is it better if I just return the Id value and let the calling procedure take care of that.

Is there a better/cleaner way of getting this done?

\$\endgroup\$
2
  • 3
    \$\begingroup\$ Is there any reason you are not using Entity Framework? \$\endgroup\$
    – t3chb0t
    Commented Sep 21, 2015 at 15:03
  • \$\begingroup\$ The project uses an implementation of NHibernate actually. Is there any functionality/technique so that I can just pass that whole object to the database using NHibernate and the Id property is automatically filled in? \$\endgroup\$
    – Adrian
    Commented Sep 22, 2015 at 6:55

2 Answers 2

1
\$\begingroup\$

I would use a slightly modified form of your option #2, which, instead of returning a modified version of the object, returns a new instance of that same entity.

  1. There are two main reasons for this. The first is that you can't be entirely sure if the data stored in your DB is exactly that of your original item. The auto-incremented ID field is new, of course, but there could be triggers, constraints or login in stored procedures that might make the data subtly different. It's best to return the newly-stored entity from the DB call and have it fully synced with the DB.

  2. The second reason is immutability. If your logic relies on updating a field in your entity after it's created, it means the ID field is mutable and can be changed elsewhere in your code. Having the class be immutable - unchangeable after instantiation - can make a lot of your logic simpler. You can have two threads operate on the same instance without worrying about race conditions between them, and other benefits beside.

Reason #2 is enough, in my opinion, to always clone your object, whether it's cloning-through-database-query or just cloning the instance before returning it.

\$\endgroup\$
1
  • \$\begingroup\$ Due to time constraints, it's not possible for me to modify the database query to return the object, but cloning it before returning it seems like a good idea. Let's say I have 10 properties for that object that need to be saved in the database, what I now have is that MetadataObject that I send as a parameter, but which also contains the Id property. Should I move the Id property to a new class then and return this new class with the Id property initialized? Seems like the obvious choice here. \$\endgroup\$
    – Adrian
    Commented Sep 23, 2015 at 6:30
0
\$\begingroup\$

option 1:

assign the Id in code, not in the database

public class MetaData
{
    public MetaData()
    {
        this.Id = Guid.NewGuid().ToString();

option 2:

return the fully populated object from the insert call on your repository

public class Repository()
{
     public MetaData Insert(MetaData md)
     {
         ///insert to db
         md.Id = returnedId
         return md;
\$\endgroup\$
1
  • \$\begingroup\$ Option 1) is not an option. I don't want to have control over what gets written in the PrimaryKey field of that table (and for practical reasons I don't have any control over the database). And 2) is basically what I also have. Thanks for your feedback. \$\endgroup\$
    – Adrian
    Commented Sep 21, 2015 at 13:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.