Archive for the tag 'C#'

Strongly typed Collections of Abstract Objects

Some of you know that we are in the process of not using Csla anymore, this is a decision that just seems logical for us, but that is another post. I need a little help implementing a problem in my domain. Now the sample I am posting is out of a dumbed down version I have been using to spike with. Take a look at the following class diagram and then I will explain what is going on and what my problem is:

Order-ClassDiagram01

What is going on here you ask? Order is the primary object type, but it is abstract. I have maybe 7 different types of orders, service order, make order, repair order, etc… each order has several attributes that are always present on every order. What makes each order unique is the attributes that are not shared between all orders. This is why I have decided to use inheritance.

One of the items that are common between all types of orders is that they all have many parts. However, I want the base Order class to have a collection of base OrderPart objects. OrderPart is the mapping object in between Order and Part for the Many To Many relationship, I am using an object because this association has state of it’s own. Now to complicate matters even more, each concrete Order can have a different concrete type of Part and OrderPart assigned to it.

I have the model all setup and Have written some tests against it as I wrote it, not really test first but hey, I am spiking here. So below is one of the tests that shows most of this in action.


public void CanCreateOrderWithCustomerAndParts()
{
var order = new CustomOrder();
order.Customer = new Customer
{
Name = "John Smith",
Address =
new Address
{
Street = "45623 Easy",
State = "TX",
City = "Dalals",
ZipCode = "73884"
}
};
order.OrderNumber = "Y984939";
order.Amount = (decimal) 1234.33;
order.CustomOrderDescription = "Testing adlkfjl 123";
order.Parts =
new List
{
new CustomOrderPart
{
Part =
new CustomPart
{
PartNumber = "Part456sdf34",
Description = "Test Partasd 87",
CustomPartText = "TEST",
},
Quantity = 12
},
new CustomOrderPart
{
Part =
new CustomPart
{
PartNumber = "PARTWITHNULLPULLLOCATION",
Description = "Test Part 848sasd8243",
CustomPartText = "TEST",
},
Quantity = 251
}
};

With.Transaction(() => Repository.Save(order));

Order createdOrder = Repository.Get(order.Id);

Assert.IsNotNull(createdOrder);
Assert.AreEqual(2, createdOrder.Parts.Count);
}

Don’t make fun of my test code, like I said, it’s a spike. But when I create a CustomOrder I am creating Parts as a new List<OrderPart> which is how it is implemented. But then I had new CustomOrderParts and CustomParts into that collection. NHibernate will persist this information correctly into the database and will retrieve it correclty from the DB. So seemingly all works fine right, sure I guess. Maybe it is just because I have been in Csla land so long that I don’t know any different but what I am really missing is being able for the concrete order object to know what concrete type of  OrderPart is contained in the parts collection. As I wrote that I just kicked myself, if that isn’t a violation of Seperation of Concerns I don’t know what is, or is it? I mean Order or a concrete Order is basically an Aggregate Root in DDD terms so it is the responsible entry point into the chain/web of objects that make up the aggregate.

So, for my real question which I am not sure of now, How would you tackle this design problem? How do you handle child collections? Am I just way off the reservation?

IRepository Code

This is by request from Frank Mao, he was wanting me to post up the code I am using for IRepository<T> so here it is:


public interface IRepository<T>
{
//IList<T> FetchList();
ICriteria CreateCriteria();
T Get(object id);
void Load(T obj, object id);
void Delete(T entity);

void DeleteAll();
void DeleteAll(DetachedCriteria where);
T Save(T entity);
T SaveOrUpdate(T entity);
T SaveOrUpdateCopy(T entity);
void Update(T entity);
long Count(DetachedCriteria criteria);
long Count();
bool Exists(DetachedCriteria criteria);
bool Exists();
IList<T> FindAll(DetachedCriteria criteria, params Order[] orders);
IList<T> FindAll(Order order, params ICriterion[] criteria);
IList<T> FindAll(Order[] orders, params ICriterion[] criteria);
T FindFirst(params Order[] orders);
T FindFirst(DetachedCriteria criteria, params Order[] orders);
T FindOne(params ICriterion[] criteria);
T FindOne(DetachedCriteria criteria);

ProjT ReportOne<ProjT>(ProjectionList projectionList);
ProjT ReportOne<ProjT>(DetachedCriteria criteria, ProjectionList projectionList);
IList<ProjT> ReportAll<ProjT>(ProjectionList projectionList);
IList<ProjT> ReportAll<ProjT>(bool distinctResults, ProjectionList projectionList);
IList<ProjT> ReportAll<ProjT>(ProjectionList projectionList, params Order[] orders);
IList<ProjT> ReportAll<ProjT>(bool distinctResults, ProjectionList projectionList, params Order[] orders);
IList<ProjT> ReportAll<ProjT>(DetachedCriteria criteria, ProjectionList projectionList, params Order[] orders);
IList<ProjT> ReportAll<ProjT>(bool distinctResults, DetachedCriteria criteria, ProjectionList projectionList, params Order[] orders);
}
}

I should note that this is a slightly modified version of IRepository that I got from the UnitOfWork tutorial code that is posted here: http://hibernatingrhinos.googlecode.com/svn/trunk/UnitOfWork/src/NHibernateRepository/

ALT.NET a College Curriculum?

There has been a lot of discussion recently on the ALT.NET list about how the ALT.NET way is so hard and complicated that it may be equivalent to a college computer science curriculum. This all started as a discussion that was geared towards building some type of cascading curriculum guide to ALT.NET software engineering principles such as TDD, S.O.L.I.D, continuous integration, unit testing, composition over inheritance, etc… I agree with this totally, We need to make some type of curriculum guide to ALT.NET principles. I am fairly new to ALT.NET and I am also fairly young. Where I work there are only two developers and we are also testers/designers/everything so when we decided that we could write better software by following the ALT.NET principles we had a hard time finding a starting place amongst all the available information. It is simply overwhelming when you are first starting, and I know we have been talking about easing the entrance barrier, but it’s just not that easy. There has to be some difficulty or is the reward is not as great in the end. However, I do believe that some type of curriculum guide would be a great tool for everyone involved with ALT.NET at any level. I think the best thing about this chart is just to show how the different principles build on each other and relate to each other so you have a reference point you can find yourself on.

Now back to the discussion on Computer Science (CS) curriculum in colleges, I graduated from a small college in Oklahoma with a degree in CS a few years ago. I personally gained a lot from college because I had a professor who had previously worked in the real world, and I worked in the real world developing software while in college so we could have intelligent conversations that only a few other students understood. This was great for me, a self motivator, but not for everybody else. I was able to demand the one on one time that I needed and to ask questions and have problems that forced the “super” students into thinking about problems other than writing a counter in a nested loop. I have now been asked to teach some software courses at the college and help, along with other alumni to revamp the curriculum that is taught in the school. In January I will begin teaching two semesters worth of ALT.NET curriculum. This will be a huge leap ahead for the students, but also for the faculty as I feel so much college faculty is out of touch with the real world anyway.

Ultimately though I think what college is really designed to do is teach students HOW to think and HOW to learn since a college cannot be expected to keep up with all the latest and greatest trends in Software engineering but it can teach students some higher level principles such as ALT.NET or at least get them started down the right path to learning ALT.NET.

SQL Server Timestamp field and Fluent-NHibernate

This morning I was trying to do a Version mapping with Fluent-NHibernate on a timestamp column in a SQL database, this didn’t work so good right out of the box so I dug around and found some information here and there and once I pieced it together it all worked.

First off the mapping:


public class ProjectMap : ClassMap<Project>, IMapGenerator
{
        public ProjectMap()
        {
            WithTable("Projects");

            Id(x => x.Id)
                .GeneratedBy
                .GuidComb()
                .WithUnsavedValue("00000000-0000-0000-0000-000000000000");

            Map(x => x.Name)
                .WithLengthOf(50)
                .CanNotBeNull();

            Map(x => x.Started);
            Map(x => x.Ended);
            Map(x => x.Description);

            Version(x => x.TimeStamp)
                .TheColumnNameIs("LastChanged");
          }

}

public override VersionPart Version(System.Linq.Expressions.Expression<Func<ProjectResource, object>> expression)
{
     var versionPart = new VersionPart(ReflectionHelper.GetProperty(expression));

     versionPart.SetAttribute("type", "ProjectTracker.Library.Mapping.UserTypeTimestamp, ProjectTracker.Library");
     versionPart.SetAttribute("generated", "always");
     versionPart.SetAttribute("unsaved-value", "null");

     AddPart(versionPart);
     return versionPart;
}
 

The main thing here is the overridden Version method. What this override is doing is setting up a few attributes required to make this all work properly, I think most of them are self explanetory. Inside this method is a set attribute method that sets the type of the timestamp to UserTypeTimestamp. The coded for this class follows below:

UserTypeTimestamp Class:


public class UserTypeTimestamp : IUserVersionType
    {
        #region IUserVersionType Members

        public object Next(object current, ISessionImplementor session)
        {
            return current;
        }

        public object Seed(ISessionImplementor session)
        {
            return new byte[8];
        }

        public object Assemble(object cached, object owner)
        {
            return DeepCopy(cached);
        }

        public object DeepCopy(object value)
        {
            return value;
        }

        public object Disassemble(object value)
        {
            return DeepCopy(value);
        }

        public int GetHashCode(object x)
        {
            return x.GetHashCode();
        }

        public bool IsMutable
        {
            get { return false; }
        }

        public object NullSafeGet(IDataReader rs, string[] names, object owner)
        {
            return rs.GetValue(rs.GetOrdinal(names[0]));
        }

        public void NullSafeSet(IDbCommand cmd, object value, int index)
        {
            NHibernateUtil.Binary.NullSafeSet(cmd, value, index);
        }

        public object Replace(object original, object target, object owner)
        {
            return original;
        }

        public System.Type ReturnedType
        {
            get { return typeof(byte[]); }
        }

        public SqlType[] SqlTypes
        {
            get { return new SqlType[] { new SqlType(DbType.Binary) }; }
        }

        public int Compare(object x, object y)
        {
            byte[] xbytes = (byte[])x;
            byte[] ybytes = (byte[])y;
            if (xbytes.Length < ybytes.Length)
            {
                return -1;
            }
            if (xbytes.Length > ybytes.Length)
            {
                return 1;
            }
            for (int i = 0; i < xbytes.Length; i++)
            {
                if (xbytes[i] < ybytes[i])
                {
                    return -1;
                }
                if (xbytes[i] > ybytes[i])
                {
                    return 1;
                }
            }
            return 0;
        }

        bool IUserType.Equals(object x, object y)
        {
            return (x == y);
        }

        #endregion
    }

Now for the Business object change this:

private byte[] timeStamp = new byte[];

To this:


private byte[] timeStamp;
internal byte[] TimeStamp
{
     get { return timeStamp; }
     set { timeStamp = value;}
}

With the addition of the class and an internal Property so NHibernate can access the data in the timestamp everything works pefectly to implement optimistic concurrency with Fluent-NHibernate and SQL Server timestamp fields.

CAB & SCSF: Maintaining Active View across Multiple workspaces

Recently I ran into a problem where I have multiple windows open in my application at once. This is great for presenting multiple views to the uesr at one time, but it is not so good for a developer trying to figure out what to do when a common toolbar command is clicked. I found some help on the internet by Chris Holmes who had come across a similar problem and thus created a solution. See: Chris Holmes - CAB: Solving the Active View Problem Chris’ solution however was only good for watching one workspace at a time. And my problem was that if I switched between MDI tabs in the MDI workspace everything was fine. But if I switched from a tab in the UltraMDITabWorkspace to a pane in the UltraDockWorkspace. The smartpart activated command never fired.

So I posted my question over in the SCSF forum and Mariano Converti replied back with his solution. Now this was great this is exaclty what I was looking for. With a little tweaking I could make this work. One problem though: Marianos solution relies on getting the workspace as a Control. Now this is great for all of the out of the box CAB Workspaces. I however am using Infragistics Workspaces, which do not derive from System.Control. So what I have here is the first of a series of posts on this subject. The code below is a service that I created in Infrastructure.Library. I will also post the interface for the service and a sample implementation. I am also going to be posting a modified version of Chris Holmes UIService that manages toolbars and menu items for an infragistics ribbon.

ActiveWorkspaceViewService.cs


[Service]
public class ActiveWorkspaceViewService : IActiveWorkspaceViewService
{
[EventPublication(EventTopicNames.ActiveViewChanged, PublicationScope.Global)]
public event EventHandler<ActiveViewChangedEventArgs> ActiveViewChanged;

IUIService _uiService;

[InjectionConstructor]
public ActiveWorkspaceViewService([ServiceDependency] IUIService uiService)
{
_uiService = uiService;
}

#region IActiveWorkspaceView Members

/// <summary>
/// Registers a Workspace to be monitored for changes such as SmartPartActivated and
/// then watches the controls for the OnEnter event
/// </summary>
/// <param name="workspace"></param>
public void AddWorkspaceToMonitor(IWorkspace workspace)
{
workspace.SmartPartActivated += new EventHandler<WorkspaceEventArgs>(OnSmartPartActivated);

if(workspace.ActiveSmartPart != null)
ActiveView = workspace.ActiveSmartPart;

}

private object _activeView;

/// <summary>
/// Returns the active SmartPart as an object
/// </summary>
public object ActiveView
{
get { return _activeView; }
private set
{
_activeView = value;
_uiService.SetActiveView((IView)value);
OnActiveViewChanged(new ActiveViewChangedEventArgs(((IView)value).Guid));
}

}

#endregion

/// <summary>
/// Handles the SmartPartActivated event for the Workspace
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnSmartPartActivated(object sender, WorkspaceEventArgs e)
{
if (e.SmartPart != null)
{
ActiveView = e.SmartPart;
Control c = e.SmartPart as Control;

c.Enter -= new EventHandler(OnEnter);
c.Enter += new EventHandler(OnEnter);

#if (DEBUG)
Console.WriteLine("SmartPart Activated: " + c.ToString());
#endif
}
}

/// <summary>
/// Provides a method of setting the smart part to the "Active"
/// SmartPart in the UIService by handling the OnEnter event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnEnter(object sender, EventArgs e)
{
Control cntrl = sender as Control;

if (cntrl != null)
{
ActiveView = cntrl;
#if (DEBUG)
Console.WriteLine("SmartPart Entered: " + cntrl.ToString());
#endif
}

}

protected virtual void OnActiveViewChanged(ActiveViewChangedEventArgs eventArgs)
{
if (ActiveViewChanged != null)
{
ActiveViewChanged(this, eventArgs);
}
}

}

IActiveWorkspaceViewService 

This is the interface for the class above.

[c#]
public interface IActiveWorkspaceViewService
{

void AddWorkspaceToMonitor(IWorkspace workspace);

object ActiveView { get; }

}
[/c#]

Now to use the service you need to register your workspaces with the service when the application starts. Make the following changes in your ShellApplication.cs file:

Put the following services in the AddServicesMethods()
[c#]RootWorkItem.Services.AddNew&amp;amp;amp;amp;amp;lt;ActiveWorkspaceViewService, IActiveWorkspaceViewService&amp;amp;amp;amp;amp;gt;(); [/c#]

The next bit of code needs to be placed in the AfterShellCreated function. This will actually register the workspace for use in the service.

[c#]/// Add the workspaces to the ActiveWorkSpace Monitor
/// This will ensure that we always know the active smartpart even
/// if switching between different workspaces
///
_activeWorkspaceService = RootWorkItem.Services.Get&amp;amp;amp;lt;IActiveWorkspaceViewService&amp;amp;amp;gt;();
_activeWorkspaceService.AddWorkspaceToMonitor(RootWorkItem.Workspaces[WorkspaceNames.MainContent]);
_activeWorkspaceService.AddWorkspaceToMonitor(RootWorkItem.Workspaces[WorkspaceNames.MainDock]); [/c#]

Like I said earlier, this is just one piece of the puzzle to make dynamic toolbars, menus and commands work across your entire application. I will post more details, source code, and a complete sample project soon.