AdFactum ObjectMapper .NET Blog

Official blog of the AdFactum ObjectMapper .NET

Exception: DirtyObjectException

Posted by Gerhard Stephan on April 17th, 2008

The DirtyObjectException will be thrown if an object is changed by another user meanwhile the object is in use by the first user. This Optimistic Locking feature is used for objects that are derived from MarkedValueObject or MarkedAutoIncValueObject.

To evaluate the feature you can force the ObjectMapper .NET to throw a DirtyObjectException.

        [Test]

        [ExpectedException(typeof(DirtyObjectException))]

        public void TestDirtyObjectException()

        {

            Buying buying = new Buying(5, "Hotdogs");

           

            using (AdFactum.Data.ObjectMapper mapper = OBM.CreateMapper(Connection))

            {

                // First save

                bool nested = OBM.BeginTransaction(mapper);

                mapper.Save(buying);

                OBM.Commit(mapper, nested);

 

                // Simulate, that an other user has changed the object

                buying.Count = 3; // the object has to be changed

                buying.LastUpdate = buying.LastUpdate.AddHours(-1);

 

                // Second save, tend to fail

                nested = OBM.BeginTransaction(mapper);

                mapper.Save(buying);

                OBM.Commit(mapper, nested);

            }

        }

Normaly you definitly would’nt change the LastUpdate Property. That’s only for showing when the DirtyObjectException will be thrown. So let us have a look at the created SQL Statement.

UPDATE [BUYING]        SET [LASTUPDATE] = CONVERT (DATETIME, '2008-04-17 20:07:46'), [COUNT] = 3
 WHERE [BUYING].[ID]=1 AND [LASTUPDATE] = CONVERT (DATETIME, '2008-04-17 19:07:46');

As you can see, the WHERE Clause contains a check condition that fails, if the object has been modified meanwhile it is in use by the current user. If that happens the DirtyObjectException will be thrown to indicate that the object has been changed.

Posted in Exceptions | No Comments »

New Release – AdFactum ObjectMapper .NET 2.3.2619.0

Posted by Gerhard Stephan on March 19th, 2008

This Release is a pure bug fixing Realease. It covers three major bug fixes.

At first, it fixes a memory leak that occures when calling the Method "BaseCache.ClearAllCaches". Because this is not obvious for all users, I have to explain that this method has been called every time the ObjectMapper class has been initialized with a version information greater than zero.

The second fix is a multithreading bug that causes the mapper to throw unmotivated Exceptions, like "NoPrimaryKeyFound" Exception and "CollectionHasBeenModified" Exception. But this only occured when using the ObjectMapper .NET in a strongly multithreaded environment.

The last fix, fixed the update and delete sql statements of dictionary types (e.g. SortedList and Hashtable). Due to that the link table had a wrong primary key definition and that caused the update of the link table to fail.

Hope you enjoy the new version.

Cheers
– Gerhard

Posted in Releases | No Comments »

Attribute: [Unicode]

Posted by Gerhard Stephan on March 7th, 2008

For all databases that supports Unicode (e.g. Oracle and Microsoft SQL Server),  a string property can be tagged with the [Unicode] attribute. The AdFactum ObjectMapper .NET does therefore use the Unicode Data Types for the specific property.

Below you’ll find all supported datatypes that can be used with the Unicode attribute.

    public class UnicodeTestEntity : ValueObject

    {

        private char unicodeChar;

        private string unicodeString;

        private string unicodeMemo;

 

        /// <summary>

        /// Gets or sets the unicode char.

        /// </summary>

        /// <value>The unicode char.</value>

        [Unicode]

        public char UnicodeChar

        {

            get { return unicodeChar; }

            set { unicodeChar = value; }

        }

 

        /// <summary>

        /// Gets or sets the unicode string.

        /// </summary>

        /// <value>The unicode string.</value>

        [Unicode]

        [PropertyLength(30)]

        public string UnicodeString

        {

            get { return unicodeString; }

            set { unicodeString = value; }

        }

 

        /// <summary>

        /// Gets or sets the unicode memo.

        /// </summary>

        /// <value>The unicode memo.</value>

        [Unicode]

        [PropertyLength(int.MaxValue)]

        public string UnicodeMemo

        {

            get { return unicodeMemo; }

            set { unicodeMemo = value; }

        }

    }

 

 

Posted in Attributes | No Comments »

Attribute: [GroupBy]

Posted by Gerhard Stephan on March 7th, 2008

The [GroupBy] attribute can be used to group properties by there value. This property can only be used in projection classes.

    /// <summary>

    /// Groups the time entries by their project id

    /// </summary>

    public class TimeEntryGrouping

    {

        private DateTime minDate;

        private string project;

 

        /// <summary>

        /// Gets or sets the min date.

        /// </summary>

        /// <value>The first date.</value>

        [ProjectOntoProperty(typeof(TimeEntry), "StartDate")]

        [Min]

        public DateTime MinDate

        {

            get { return minDate; }

            set { minDate = value; }

        }

 

        /// <summary>

        /// Gets or sets the project.

        /// </summary>

        /// <value>The project.</value>

        [ProjectOntoProperty(typeof(TimeEntry), "ProjectId")]

        [GroupBy]

        public string Project

        {

            get { return project; }

            set { project = value;  }

        }

    }

 

Select the grouping:

 

                List<TimeEntryGrouping> result =

                    new List<TimeEntryGrouping>(

                        new ListAdapter<TimeEntryGrouping>(

                    mapper.FlatSelect(typeof(TimeEntryGrouping))));

 

Posted in Attributes | No Comments »

Attribute: [Avg], [Count], [First], [Last], [Max], [Min] and [Sum]

Posted by Gerhard Stephan on March 7th, 2008

This aggregation attributes can be placed on any projection property of a projection class.

    public class TimeEntryAggregation

    {

        private DateTime minDate;

 

        /// <summary>

        /// Gets or sets the min date.

        /// </summary>

        /// <value>The first date.</value>

        [ProjectOntoProperty(typeof(TimeEntry), "StartDate")]

        [Min]

        public DateTime MinDate

        {

            get { return minDate; }

            set { minDate = value; }

        }

    }

    var minTimeEntry = mapper.Load(typeof(TimeEntryAggregation), null as ICondition) as TimeEntryAggregation;

 
The following attributes can be used this way:

  • [Avg] 
  • [Count]
  • [First], [Last]
  • [Min], [Max]
  • [Sum]

Posted in Attributes | No Comments »

New Release – AdFactum ObjectMapper .NET 2.3.2607.0

Posted by Gerhard Stephan on March 7th, 2008

Today, the AdFactum ObjectMapper .NET reaches the next evolution level – hmm – I mean: the next release. But without joking, it’s a big step to a full integrated LINQ support and a big step further to complete the base functionality of the AdFactum ObjectMapper .NET.

First I implemented the base aggregation functions like Min, Max, First, Last, Sum and Count and grouping functionality with using the GroupBy Clause. This functionality can be used with projection classes or directly using the new Linq Syntax. The only thing that is still missing, is the Having Clause which caused me a lot of headache. But I’m confident that I can implement that feature in the next release.

As a second new feature, the AdFactum ObjectMapper .NET now offers Unicode support for Oracle and Microsoft SQL Server. To use this new feature, the properties must be tagged with an [Unicode] attribute.

Hope you enjoy the new version.

Cheers
– Gerhard

Posted in Releases | No Comments »

New Release – AdFactum ObjectMapper .NET 2.2.2519.0

Posted by Gerhard Stephan on February 19th, 2008

This release covers two bug fixes. The first one fixes a bug within the projection query engine, which prevents selecting a projection multiple times due to a null pointer exception that has been thrown by the ObjectMapper .NET. The second one fixes the short name generation in the repository part of the ObjectMapper .NET.

I think that is the last bug fix release before the next bigger release introduces many enhancements to the AdFactum ObjectMapper .NET.

For the record:

  • It’s planned to support the aggregation functions, like min(), max(), sum() and so on.
  • It’s planned to support 1 to many relations between parent and child, instead of only supporting the n:m relations.

So, I hope you enjoy the calm before the storm (before the next release 😉 and wish you a successfull week.

Cheers
– Gerhard

Posted in Releases | No Comments »

Best practice for designing compositions, aggregations and associations between entities.

Posted by Gerhard Stephan on February 4th, 2008

Designing the data model can be a complex task. Specially if you think about how to bind entities together. You can bind entities together by using an composition, an aggregation or by creating an association between them. But what is the difference? And how does this affect the design of the data model?

In this post, I want to clarify the difference between composition, aggregation and association, and to show the difference of implementation. The definitions are taken from the Wikipedia.org (http://en.wikipedia.org/wiki/Class_diagram#Association)

Definitions:

Composition is a stronger variant of the "has a" or association relationship; composition is more specific than aggregation. Composition has a strong life cycle dependency between instances of the container class and instances of the contained class(es): If the container is destroyed, every instance that it contains is destroyed as well.

Aggregation is a variant of the "has a" or association relationship; aggregation is more specific than association. Aggregation can occur when a class is a collection or container of other classes, but where the contained classes do not have a strong life cycle dependency on the container–essentially, if the container is destroyed, its contents are not.

An Association can be named, and the ends of an association can be adorned with role names, ownership indicators, multiplicity, visibility, and other properties. There are five different types of association. Bi-directional and uni-directional associations are the most common ones. For instance, a flight class is associated with a plane class bi-directionally. Associations can only be shown on class diagrams.

What does this mean to the data model design?

Compositions and Aggregations are the strongest relationships. E.g. if you think of an Employee, the employee owns a work time model. If the employee will be fired, his work time modell will be deleted as well.

In that case you would directly place the work time model into the users entity. This has the advantage, that you can directly deep load the user, change the work model composition and store the changes to database.

    public class Employee : ValueObject

    {

        private WorkTimeModel worktimeModel;

 

        /// <summary>

        /// Gets or sets the worktime model.

        /// </summary>

        /// <value>The worktime model.</value>

        public WorkTimeModel WorktimeModel

        {

            get { return worktimeModel; }

            set { worktimeModel = value; }

        }

    }

 

In case of compositions you can delete the depending work time model directly when removing the employee from database. Therefore you can call the mothod : DeleteRecursive

Now back to our example. Think of a time entry. A time entry is always associated to an employee, but it does not own the employee. That mean, it does not aggregate the employee. If you delete a time entry, the user won’t be deleted. In that case it’s better to use a loose couple between the class TimeEntry and Employee.

    public class TimeEntry : ValueObject

    {

        private Guid employeeId;

 

        /// <summary>

        /// Gets or sets the employeeId.

        /// </summary>

        /// <value>The employeeId.</value>

        [ForeignKey(typeof(Employee), "Id")]

        public Guid EmployeeId

        {

            get { return employeeId; }

            set { employeeId = value; }

        }

    }

 

The [ForeignKey] attribute ensures, that the stored Property uses a foreign key to the Employee table. If you still need further informations of the employee who is associated, you can use a VirtualLink to join the employee table to the Time Entry.

    public class TimeEntry : ValueObject

    {

        private Guid employeeId;

        private string name;

 

        /// <summary>

        /// Gets or sets the employeeId.

        /// </summary>

        /// <value>The employeeId.</value>

        [ForeignKey(typeof(Employee), "Id")]

        public Guid EmployeeId

        {

            get { return employeeId; }

            set { employeeId = value; }

        }

 

        /// <summary>

        /// Gets or sets the name of the employee.

        /// </summary>

        /// <value>The name.</value>

        [VirtualLink(typeof(Employee), "Id", "Name", "EmployeeId")]

        public string Name

        {

            get { return name; }

            set { name = value; }

        }

    }

Conclusion

If you use this pattern in all your entities, you can load the entities most times without specifiing an hierarchy level. The advantage are more clearly designed business components that are much easier to understand.

I wish you a successfull time.

Cheers
 – Gerhard

Posted in Hint | No Comments »

New Release – AdFactum ObjectMapper .NET 2.2.2430.0

Posted by Gerhard Stephan on January 30th, 2008

This version contains two new changes.

The first, is included because of the backward compatibility to earlier versions where the AdFactum ObjectMapper .NET did only support GUID types as Primary Keys. To satisfy our customers which upgraded to the new version the last days, I included a backward compatibility modus. The rule: If no primary key is defined within an interface, assume that the primary key must be a GUID.

The second new feature is a new overload to the ExecuteScript Method, which now takes an OnSqlFileFailed Delegate to handle exceptions thrown when executing the sql file.

Hope you enjoy the new version.
Cheers

– Gerhard

Posted in Releases | No Comments »

Exception: NoPrimaryKeyFoundException

Posted by Gerhard Stephan on January 28th, 2008

The NoPrimaryKeyFoundException will be thrown if the user tries to query an entity type which has no valid primary key defined by the PrimaryKey attribute. In case that you use a pre-defined base object like "AutoIncValueObject" or "ValueObject" this exception will never occure.

To solve this exception, include a property to your entity type which is tagged with the PrimaryKey attribute or use a pre-defined base class.

    /// <summary>

    /// Interface that describes a person

    /// </summary>

    public interface IPerson : IValueObject

    {

        /// <summary>

        /// Gets or sets the unique value object id.

        /// </summary>

        /// <value>The unique value object id.</value>

        [PrimaryKey]

        new int? Id

        {

            get;

            set;

        }

 

Posted in Exceptions | No Comments »