CRM Development

Solutionist has designed the architecture for a new CRM system for use in the medical imaging industry.

Thursday, 8 September 2011

Entity Framework Tip #1 - Using MergeOption to get latest entities

Hopefully this is the first of various Entity Framework tips that I've gleaned along the way.
They'll serve as reminders for me and if they can help other people, they will have served their purpose.


Ok, what's wrong with this?

(We're using STEs because we're throwing things across the network). 
I was doing some testing and had code that looked like this.

 DBEntities context1 = new DBEntities();
 
 DBEntities context2 = new DBEntities();
 Site newSite = new Site();
 newSite.SiteName = "QAZ";
 
 context1.Sites.AddObject(newSite);
 context1.ApplyChanges("Sites", newSite);
 context1.SaveChanges();
 
 Site site2 = context2.Sites.Where(s => s.ID == newSite.ID).FirstOrDefault();
 
 // update the site...
 site2.ChangeTracker.ChangeTrackingEnabled = true; // Because they're STEs
 site2.SiteName = "QAZ QAZ";
 context2.ApplyChanges("Sites", site2);
 context2.SaveChanges();
 
 
 // I thought I'd use the first context to query for the updated site...
 
 var query = context1.Sites.Where(s => s.ID == newSite.ID);
 Site site3 = query.FirstOrDefault();

What's the SiteName of site3?

No, it's not "QAZ QAZ" - it's "QAZ"

Why is that? 

Because the site already exists in context1 - so even though a database query is actually executed, EF will not overwrite what's in context1 because its cache already contains an entity with that EntityKey.

How to make sure that I actually get the latest values back?

Set the MergeOption on the objectSet before doing the call - as follows...
context1.Sites.MergeOption = MergeOption.OverwriteChanges;

The default option is AppendOnly which won't update the context if it finds an entity with the
same entityKey present.

Another tip from the twighlight world of entity framework...

One thing I've yet to investigate is how delayed execution would affect MergOption settings.
So, if I reset the MergeOption after the query to AppendOnly and then do further queries before finally executing the query - would the different MergeOptions be applied at the right time... hmmm...


 

Tuesday, 7 June 2011

.NET IoC - part 3 (Spring)

It's been some time, but this is continuing my previous posts about .NET IoC.

As I'm familiar with Spring from the Java world, I thought I'd transfer that knowledge across to .NET. It turned out to be less painful than I expected.

I was building a service-based project and used spring on both the client and server sides of the divide. For this post, I'll initially stick to it's use on the client side, but server-side has a very similar set-up. Maybe I'll come to full WCF integration later on.

For basic IoC you just need the Spring.Core.dll from the distribution - add this as a reference to your project.

Initially I'm following the KISS principle, so I created a basic application context file - spring.config.xml and put that at the top level of my project.

Basic format is as follows:

<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net">

<object id="Object1"
type="<Assembly name>.namespace.classname1, <assembly name>" singleton="false">

<property name="Property1"  ref="Object2" />
</object>


<object id="Object2"
type="<Assembly name>.namespace.classname2, <assembly name>" singleton="false">

</object>

</objects>


The singleton="false" will ensure that Spring gives you a new instance every time you request the particular object.

As a minimum in your code, you'll need to create an application context somewhere.
I've put it in a singleton Locator class as follows:

private static IApplicationContext _context = null;
_context = new XmlApplicationContext("spring-config.xml");

where spring-config.xml is the name of your config file. This is sitting at the top-level of the project.

Then you'll want a method to grab hold of an object instance as follows:

public object getObjectInstance(string name)
{
  return _context.GetObject(name);
}

or, if you need to pass arguments in to the constructor...

public object getObjectInstance(string name, object[] args)
{
  return _context.GetObject(name, args);
}

In both cases "name" is the object's ID in the configuration file.
Passing arguments in like this is "OK", but can be a pain, since there's no compile time checking - but we're staying simple.

At some point you could call:

Locator.Instance.getObjectInstance("Object1");


This will:
  • create an instance of Object1
  • create an instance of Object2
  • set Property1 on Object1 to be Object2
  • return you a "ready-to-go" instance of Object1.
 These are your absolute basics. But hopefully this will put you on the road.

Wednesday, 12 January 2011

.Net IoC - part 2 (StructureMap)

It's been some time since I've last posted anything up, but I thought I'd put up a bit more about my
working with IoC in .NET.

In a previous post I mentioned that I'd come across Spring.NET, Unity and StructureMap
I wanted something that I could pick up easily and which focused on IoC. 


Starting to using it fairly simple. 
  1. You reference the structuremap dll
  2. Add something looking like this into your code... I wrapped it up in a Singleton to give me more flexibility.. 
public sealed class Locator     {
        private static volatile Locator _instance = null;         private static object syncRoot = new Object();


        private static Container objectFactory = null; 
        private Locator()
        {
            objectFactory = new Container(
                 x =>
                 {

                    x.For<myservice>().Use<myserviceclient>();                        </myserviceclient></myservice>
 
                     x.For<ihelper>().Use<realhelper>();
  
                     x.For<iinterface1>().Use<implementation1>()
                         .Setter().IsTheDefault();
                 });
        }
 
        public static Locator Instance
        {
            get 
            {         
                if (_instance == null) 
                {            
                    lock (syncRoot)             
                    {               
                        if (_instance == null)                   
                            _instance = new Locator();            
                    }         
                }         
                return _instance;      
            }
        }
 
        public object getObjectInstance()
        {

            return objectFactory.GetInstance();
        }
 

        public object getObjectInstance(Dictionary items)
        {

            var args = new ExplicitArguments();
 
            foreach (var item in items)
            {
                //args.Set(item);
                args.SetArg(item.Key, item.Value);
            }
            return objectFactory.GetInstance(args);
        }


In code I'm calling:
Locator.Instance.getObjectInstance()


The second method allow you to pass in constructor parameters.


All this means I can remove references to StructureMap from my Code and, if need be,
swap out IoC containters without affecting the rest of the code. In fact, this happened eventually.

StructureMap looked a good candidate, the fluent interface is nice and there's no XML if you don't want it! But, I did find the that the lack of decent documentation was an issue.
There was a lot of information - but scattered around. I didn't want to spent ages hunting stuff down.


Unity, I'm afraid, seemed over complicated. I'm still getting my head round other .Net stuff and I wanted to minimise the amount to learn. 


That left Spring.... which, all being well, I'll cover in part 3.

Monday, 20 September 2010

Early Entity Framework thoughts

It's been a few weeks since my last post, but I've been reading and working with a couple of good books.


One of those was O'Reilly's Programming Entity Framework (ISBN 9780596807276).
It's not an easy read, but, then again, it's not really meant to be. The topic is huge with ramifications  across any multi-tier application.
I'm currently looking at an N-tier app with a combination of WPF, Silverlight and ASP.NET presentation layers, so having the underlying technology and architecture right is critical.
With that in mind, the sections on WCF RIA and Data services are very helpful and the worked examples are excellent to go through.


Now, behind all this is a niggle along the lines of "I've seen this before"... where? 
Well, Hibernate's been around Java world some time (Nhibernate more recently for MS) and, before that, you have J2EE's early awkward/abortive (choose your adjective) attempts at ORM using EJB 1 and 2. 
EJB3 and Hibernate now provide a data access layer with Spring or EJB3 session beans sitting above that providing declarative transaction management and access control. 
We had Data Transfer Objects (DTOs) for passing data across layers.


Moving across to .NET4 we have the DTO equivalent - i.e. POCOs or STEs or RIA Services' own cross-tier mechanism. You also have EF4 providing the ORM and data access, then WCF in it's various forms provides the service/session layer.


So, for N-tier apps, I get a feeling of it being a case of "Hello Microsoft, welcome to my world!".
It's early days and I'll see how this all goes in MS-land. Having done some prototyping, I have to say is that the MS tooling goes a good way to smoothing out a lot of bumps in the road. 
I'm still waiting for Netbeans/Eclipse/MyEclipse to get to the level of Visual Studio tooling - especially when developing UIs. 


See you back here soon.
 

Tuesday, 10 August 2010

Quartz.NET

  I haven't got round to trying Spring.NET yet, but had a play with another Java-to-.NET port: Quartz.NET.

I'm sure that there are other posts/tutorials about how to get it working, but I'll add in my twopennyworth as a step-by-step account of what I did.

1. Downloaded latest version of Quartz.NET - 1.0.2
2. Using VS2010, I created a Web Project and added references to the Quartz and Common.Logging dll's that are in the bin directory
3. For good measure I also added a reference to the log4net dll - I would be using this in the Quartz job.
4. For log4net config, I kept this separate from the application and placed a log4net.config file in project. I then referenced this in Global.asax as follows:

log4net.Config.DOMConfigurator.ConfigureAndWatch(new System.IO.FileInfo(AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "log4net.config"));

My log4net config file looked like:





<?xml version="1.0" encoding="utf-8" ?>
<log4net>
  <root>
    <level value="DEBUG" />
    <appender-ref ref="RollingFileAppender"/>
  </root>

  <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
    <file value="logs\Logfile.log" />
    <appendToFile value="true" />
    <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
    <rollingStyle value="Composite"/>
    <datePattern value="yyyyMMdd"/>
    <maxSizeRollBackups value="10" />
    <maximumFileSize value="1000KB" />
    <staticLogFileName value="true" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%d [%t]%-5p %c [%x] - %m%n" />
    </layout>
  </appender>

</log4net>



5. Ran the database script (for SQL server) to create the relevant tables.

6. Updated the Web. Config file as follows:




  <configSections>

    <section name="quartz" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" />
  </configSections>







  <quartz>
    <add key="quartz.scheduler.instanceName" value="CommerceScheduler" />
    <!-- Configure Thread Pool -->
    <add key="quartz.threadPool.type" value="Quartz.Simpl.SimpleThreadPool, Quartz" />
    <add key="quartz.threadPool.threadCount" value="10" />
    <add key="quartz.threadPool.threadPriority" value="Normal" />
    <!-- Configure Job Store -->
    <add key="quartz.jobStore.misfireThreshold" value="60000" />
    <!--<add key="quartz.jobStore.type" value="Quartz.Simpl.RAMJobStore, Quartz" />-->
    <add key="quartz.jobStore.type" value="Quartz.Impl.AdoJobStore.JobStoreTX, Quartz" />
    <add key="quartz.jobStore.dataSource" value="default" />
    <add key="quartz.jobStore.tablePrefix" value="QRTZ_" />
    <add key="quartz.jobStore.clustered" value="true" />
    <add key="quartz.jobStore.lockHandler.type" value="Quartz.Impl.AdoJobStore.UpdateLockRowSemaphore, Quartz" />
    <add key="quartz.jobStore.driverDelegateType" value="Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz" />
    <add key="quartz.dataSource.default.connectionString" value="Data Source=Server_Name;Initial Catalog=quartz;Integrated Security=True" />
    <add key="quartz.dataSource.default.provider" value="SqlServer-20" />
    <add key="quartz.jobStore.useProperties" value="true" />
         </quartz>



7. Created a test job:


public class QuartzJob1 : IJob
{
  protected static log4net.ILog log =      log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

  void IJob.Execute(JobExecutionContext context)
  {
    log.Debug("QuartzJob1 run");
  }
}

8. For testing purposes created a class with the following static method.

public static void InitQuartz()
{
    // construct a scheduler factory
    ISchedulerFactory schedFact = new StdSchedulerFactory();

    // get a scheduler
    IScheduler sched = schedFact.GetScheduler();
    sched.Start();

    // construct job info
    JobDetail jobDetail = new JobDetail("myJob", null, typeof(QuartzJob1));
    // fire every hour
    Trigger trigger = TriggerUtils.MakeMinutelyTrigger();
    // start on the next even hour
    trigger.StartTimeUtc = TriggerUtils.GetNextGivenMinuteDate(DateTime.UtcNow, 1);
    trigger.Name = "myTrigger";
    sched.ScheduleJob(jobDetail, trigger);
}

9. Global.asax added a call to InitQuartz()

10. Ran the application.

You should see a log message being written out every minute.
And you should see entries in the
QRTZ_SIMPLE_TRIGGERS and QRTZ_FIRED_TRIGGERS tables.




Friday, 6 August 2010

RIA Services and ASP.NET

I've been looking at WCF RIA services for a new project - and looking at seeing if I can use the DomainService on an ASP.NET page directly.

This gets you to a half-way house situation where you have your middle-tier, but don't have to learn Silverlight just yet. It's not immediately obvious where to start, but you need to get hold of the RIA services toolkit (for SL4... I'm working with VS2010) - which then gives you a DomainDataSource available for use on .aspx pages.

So.... created my DomainService with a couple of related entities.
pulled in a couple of DomainDataSources for the master and detail queries and hooked up a grid for the master query and DetailView for the detail.

The basic concept worked fine!

But.. then I tried to enable paging and sorting in the master and detail view and got this error

The method ‘Skip’ is only supported for sorted input in LINQ to Entities. The method ‘OrderBy’ must be called before the method ‘Skip’.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.NotSupportedException: The method ‘Skip’ is only supported for sorted input in LINQ to Entities. The method ‘OrderBy’ must be called before the method ‘Skip’.
Hmmm....

It turns out (thanks to this link) that you need to add some default ordering to your query methods in the DomainService. This enforces the ordering before any other modifier.

Wednesday, 4 August 2010

Training

Running an ASP.NET training course recently got me thinking about the range of skills someone needs nowadays working in IT.

The students came from a wide range of backgrounds - some with more or less development experience, but the range of topics we were covering on was huge:
  • HTML
  • Javascript
  • C#
  • OO concepts
  • XML
  • Security
  • Database access
  • Visual Studio IDE (a course in itself!)
... and we're not even talking about particularly complex sites.
If you are talking about complex enterprise applications, then you're into services (of varying kinds), AJAX, async messaging, enterprise integration, design patterns, various competing Microsoft and Java/J2EE technologies, etc, etc

I've picked this up over many years in the industry - these students are faced with a bewildering array of information to absorb at the outset. Unfortunately, all too often, potential employers want to see the "finished" article - but it doesn't happen overnight.

I wish them well on their chosen career path - if they appreciate that being in IT means being willing to look at new ideas and continue learning, then they're a good part of the way there to appreciating what IT is as a profession.