Wednesday, 9 December 2015

Generic Entity Framework CRUD Baseclass

Often a lot of time is done in Entity Framework by doing the same tedious mapping procedure to and from the database to POCO entities that are returned to the consumers, such as data contracts. Let us investigate a way to do this is in a more generic way. First, we create an interface for the CRUD operations we will support.

using System.Collections.Generic;

namespace SomeAcme.Data.EntityFramework
{

    public interface IDefaultDbCrudOperation<TEntity, TDataContract>
        where TEntity : class
        where TDataContract : class
    {

        List<TDataContract> GetAll();

        TDataContract InsertOrUpdate(TDataContract dataContract);

        bool Delete(TDataContract entity);

        List<TDataContract> InsertOrUpdateMany(List<TDataContract> dataContracts); 

    }

}

Next off, we need to provide the implementation itself, I choose here to support DbContext and not ObjectContext in EF:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using SomeAcme.Common;
using System.ComponentModel.DataAnnotations;

namespace Nonline.Data.EntityFramework
{

    public class BaseDataManager<TEntity, TDataContract> : IDefaultDbCrudOperation<TEntity, TDataContract> 
        where TEntity : class, new()
        where TDataContract : class
    {

        public bool Delete(TDataContract dataContract)
        {
            using (var ctx = new SvarrapportEntities())
            {
                var primaryKey = GetPrimaryKey(dataContract); 
                var entityFound = ctx.Set<TEntity>().Find(primaryKey);
                if (entityFound == null)
                    return false; 
                ctx.Set<TEntity>().Remove(entityFound);
                ctx.SaveChanges(); 
                return true;
            }
        }

        public List<TDataContract> GetAll()
        {
            using (var ctx = new SvarrapportEntities())
            {
                return ctx.Set<TEntity>().Project().To<TDataContract>().ToList();
            }
        }

        public TDataContract InsertOrUpdate(TDataContract dataContract)
        {
            using (var ctx = new SvarrapportEntities())
            {
                var primaryKey = GetPrimaryKey(dataContract);
                var foundEntity = ctx.Set<TEntity>().Find(primaryKey);
                bool isNew = foundEntity == null;

                foundEntity = Queryable.AsQueryable(new[] { dataContract }).Project().To<TEntity>().First();

                if (isNew)
                    ctx.Set<TEntity>().Add(foundEntity);

                ctx.SaveChanges();

                return Queryable.AsQueryable(new[] { foundEntity }).Project().To<TDataContract>().First();
            }
        }

        public List<TDataContract> InsertOrUpdateMany(List<TDataContract> dataContracts)
        {
            if (dataContracts == null)
                throw new ArgumentNullException("An empty list was provided!");
            var changesMade = new List<TDataContract>();
            foreach (var dc in dataContracts)
                changesMade.Add(InsertOrUpdate(dc)); //Simple logic in this case 
            return changesMade; 
        }

        private object GetPrimaryKey(TDataContract entity) 
        {
            PropertyDescriptor pDesc = TypeDescriptor.GetProperties(entity).Cast<PropertyDescriptor>().FirstOrDefault(p => p.HasAttribute<KeyAttribute>());
            if (pDesc == null)
                throw new InvalidOperationException("Provided datacontract must have one column with Key attribute!");

            var primaryKey = pDesc.GetValue(entity);
            return primaryKey; 
        }

    }

}



Note here that I use code from another article of mine, Automatic Mapping for Deep Objects in EF, where you see the Project() and To() methods. Here is that code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text.RegularExpressions;

namespace SomeAcme.Data.EntityFramework
{

    /// <summary>
    /// Enables auto mapping features in Entity Framework
    /// </summary>
    /// <remarks>More information here: http://toreaurstad.blogspot.no/2015/02/automatic-mapping-for-deep-object.html </remarks>
    public static class QueryableExtensions
    {
        public static ProjectionExpression<TSource> Project<TSource>(this IQueryable<TSource> source)
        {
            return new ProjectionExpression<TSource>(source);
        }
    }

    public class ProjectionExpression<TSource>
    {
        private static readonly Dictionary<string, Expression> _expressionCache = new Dictionary<string, Expression>();

        private readonly IQueryable<TSource> _source;

        public ProjectionExpression(IQueryable<TSource> source)
        {
            _source = source;
        }

        public IQueryable<TDest> To<TDest>()
        {
            var queryExpression = GetCachedExpression<TDest>() ?? BuildExpression<TDest>();

            return _source.Select(queryExpression);
        }

        private static Expression<Func<TSource, TDest>> GetCachedExpression<TDest>()
        {
            var key = GetCacheKey<TDest>();

            return _expressionCache.ContainsKey(key) ? _expressionCache[key] as Expression<Func<TSource, TDest>> : null;
        }

        private static Expression<Func<TSource, TDest>> BuildExpression<TDest>()
        {
            var sourceProperties = typeof(TSource).GetProperties();
            var destinationProperties = typeof(TDest).GetProperties().Where(dest => dest.CanWrite);
            var parameterExpression = Expression.Parameter(typeof(TSource), "src");

            var bindings = destinationProperties
                                .Select(destinationProperty => BuildBinding(parameterExpression, destinationProperty, sourceProperties))
                                .Where(binding => binding != null);

            var expression = Expression.Lambda<Func<TSource, TDest>>(Expression.MemberInit(Expression.New(typeof(TDest)), bindings), parameterExpression);

            var key = GetCacheKey<TDest>();

            _expressionCache.Add(key, expression);

            return expression;
        }

        private static MemberAssignment BuildBinding(Expression parameterExpression, MemberInfo destinationProperty, IEnumerable<PropertyInfo> sourceProperties)
        {
            var sourceProperty = sourceProperties.FirstOrDefault(src => src.Name == destinationProperty.Name);

            if (sourceProperty != null)
            {
                return Expression.Bind(destinationProperty, Expression.Property(parameterExpression, sourceProperty));
            }

            var propertyNameComponents = SplitCamelCase(destinationProperty.Name);

            if (propertyNameComponents.Length >= 2)
            {
                sourceProperty = sourceProperties.FirstOrDefault(src => src.Name == propertyNameComponents[0]);
                if (sourceProperty == null)
                    return null;

                var propertyPath = new List<PropertyInfo> { sourceProperty };
                TraversePropertyPath(propertyPath, propertyNameComponents, sourceProperty);

                if (propertyPath.Count != propertyNameComponents.Length)
                    return null; //must be able to identify the path 

                MemberExpression compoundExpression = null;

                for (int i = 0; i < propertyPath.Count; i++)
                {
                    compoundExpression = i == 0 ? Expression.Property(parameterExpression, propertyPath[0]) :
                        Expression.Property(compoundExpression, propertyPath[i]);
                }

                return compoundExpression != null ? Expression.Bind(destinationProperty, compoundExpression) : null;
            }

            return null;
        }

        private static List<PropertyInfo> TraversePropertyPath(List<PropertyInfo> propertyPath, string[] propertyNames,
            PropertyInfo currentPropertyInfo, int currentDepth = 1)
        {
            if (currentDepth >= propertyNames.Count() || currentPropertyInfo == null)
                return propertyPath; //do not go deeper into the object graph

            PropertyInfo subPropertyInfo = currentPropertyInfo.PropertyType.GetProperties().FirstOrDefault(src => src.Name == propertyNames[currentDepth]);
            if (subPropertyInfo == null)
                return null; //The property to look for was not found at a given depth 

            propertyPath.Add(subPropertyInfo);

            return TraversePropertyPath(propertyPath, propertyNames, subPropertyInfo, ++currentDepth);
        }

        private static string GetCacheKey<TDest>()
        {
            return string.Concat(typeof(TSource).FullName, typeof(TDest).FullName);
        }

        private static string[] SplitCamelCase(string input)
        {
            return Regex.Replace(input, "([A-Z])", " $1", RegexOptions.Compiled).Trim().Split(' ');
        }

    }

}


Now, all you have to do create a basic CRUD-supporting Entity Framework Manager is to inherit from the base class above and specify which entity and data contract type you will support. Note that the mapping utilitizes demands that you match your property names of the data contract with the columns in the database (e.g. entity properties), in addition to their types. Also, note that you can map deep objects by using a camel case convention, see the previously mentioned article for the details. I have added four methods:
  • GetAll()
  • InsertOrUpdate()
  • Delete()
  • InsertOrUpdateMany()
Note that you have to decorate ONE property of your data contracts with the System.ComponentModel.DataAnnotations.KeyAttribute! The attribute is found in the System.ComponentModel.DataAnnotations DLL. Some additional code:

 public class Singleton<T> where T : new()
    {
        private static readonly T instance;

        static Singleton()
        {
            instance = new T();
        }

        public static T Instance
        {
            get { return instance; }
        }

        private Singleton()
        {

        }

    } //class Singleton<T> 


using System.Configuration;
using System.Diagnostics;

namespace SomeAcme.Common.Logging
{

    /// <summary>
    /// Facade class to log information, warnings and exceptions to the event log
    /// </summary>
    /// <remarks>Based upon Microsoft Prism Logger Facade </remarks>
    public class EventLogFacade : ILoggerFacade
    {

        public const int MaxLogMessageLength = 32765;

        public string EventLogSourceName;

        public EventLogFacade()
        {
            EventLogSourceName = ConfigurationManager.AppSettings[Constants.EventLogSourceNameKey];
         
            if (!EventLog.SourceExists(EventLogSourceName))
            {
                EventLog.CreateEventSource(EventLogSourceName, Constants.Application);
            }
        }

        private void WriteEntry(string message, Category category, Priority priority)
        {
            int eventID = 0;
            if (!string.IsNullOrEmpty(message) && message.Length >= (MaxLogMessageLength))
                message = message.Substring(0, MaxLogMessageLength - 1); //Limit in how large Event Log Items can be 

            EventLog.WriteEntry(EventLogSourceName, message, GetEventLogEntryType(category), eventID, GetPriorityId(priority));
        }

        private static EventLogEntryType GetEventLogEntryType(Category category)
        {
            switch (category)
            {
                case Category.Debug:
                    return EventLogEntryType.Information;
                case Category.Exception:
                    return EventLogEntryType.Error;
                case Category.Info:
                    return EventLogEntryType.Information;
                case Category.Warn:
                    return EventLogEntryType.Warning;
                default:
                    return EventLogEntryType.Error;
            }
        }

        private static short GetPriorityId(Priority priority)
        {
            switch (priority)
            {
                case Priority.None:
                    return 0;
                case Priority.High:
                    return 1;
                case Priority.Medium:
                    return 2;
                case Priority.Low:
                    return 3;
                default:
                    return 0;
            }
        }

        public void Log(string message, Category category = Category.Exception, Priority priority = Priority.High)
        {
            WriteEntry(message, category, priority);
        }

    }

}



Sadly, lists inside data contracts are not being auto mapped for now. Otherwise, the code above should in theory make mapping back and forth between those data contracts and entities in EF way easier now! Good luck!

Wednesday, 25 November 2015

Locking and unlocking specific bytes of a file in C#

The following code shows a program that can lock and unlock specific bytes of file in C# using FileStream::Lock and FileStream::Unlock in System.IO. To test out that locking can protect designated bytes of a file, start up multiple instances of the program and try writing to the file after it has been locked. This will protect the file to be modified by other processes, which is handy if you want to ensure data integrity of files your system or application uses and expect to have a given contents and format. FileStream class allows us to work on files on a byte level and do detailed I/O operations on files in .NET.


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestOutFileLocking
{

    class FStreamLock
    {

        static void Main(string[] args)
        {
            var uniEncoding = new UnicodeEncoding();
            string lastRecordText = "The last processed record number was: ";
            int textLength = uniEncoding.GetByteCount(lastRecordText);
            int recordNumber = 13;
            int byteCount = uniEncoding.GetByteCount(recordNumber.ToString());
            string tempString;

            using (var fileStream = new FileStream("Test#@@#.dat", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
            {
                //Write the original file data. 
                if (fileStream.Length == 0)
                {
                    tempString = lastRecordText + recordNumber.ToString(); 
                    fileStream.Write(uniEncoding.GetBytes(tempString), 0, uniEncoding.GetByteCount(tempString));
                }

                //Allow the user to choose the operation. 
                char consoleInput = 'R'; 
                byte[] readText = new byte[fileStream.Length];
                while (consoleInput != 'X')
                {
                    Console.Write("\nEnter 'R' to read, 'W' to write, 'L' to " + "lock, 'U' to unlock, anything else to exit: ");

                    if ((tempString = Console.ReadLine()).Length == 0)
                    {
                        break;
                    }
                    consoleInput = char.ToUpper(tempString[0]);

                    switch (consoleInput)
                    {
                        //Read data from the file and 
                        //write it to the console 
                        case 'R':
                            try
                            {
                                fileStream.Seek(0, SeekOrigin.Begin);
                                fileStream.Read(readText, 0, (int) fileStream.Length);
                                tempString = new string(uniEncoding.GetChars(readText, 0, readText.Length));
                                Console.WriteLine(tempString);
                                recordNumber = int.Parse(tempString.Substring(tempString.IndexOf(':') + 2)); 

                            }
                            //Catch the IOException generated if the 
                            //specified part of the file is locked. 
                            catch (IOException e)
                            {
                                Console.WriteLine("{0}: The read " +
                                 "operation could not be performed " +
                                 "because the specified part of the " +
                                 "file is locked.",
                                 e.GetType().Name);
                                
                            }

                            break;

                            //Update the file. 
                        case 'W':

                            try
                            {
                                fileStream.Seek(textLength, SeekOrigin.Begin);
                                fileStream.Read(readText, textLength - 1, byteCount);
                                tempString = new string(uniEncoding.GetChars(readText, textLength - 1, byteCount));
                                recordNumber = int.Parse(tempString) + 1;
                                fileStream.Seek(textLength, SeekOrigin.Begin);
                                fileStream.Write(uniEncoding.GetBytes(recordNumber.ToString()), 0, byteCount);
                                fileStream.Flush(); 
                                Console.WriteLine("Record has een updated.");
                            }
                            catch (IOException e)
                            {
                                Console.WriteLine(
                                    "{0}: The write operation could not " +
                                    "be performed because the specified " +
                                    "part of the file is locked.",
                                    e.GetType().Name);
                            } //try-catch 
                            break;

                            //Lock the specified part of the file. 
                        case 'L':

                            try
                            {
                                fileStream.Lock(textLength - 1, byteCount);
                                Console.WriteLine("The specified part " + "of file has been locked.");
                            }
                            catch (IOException err)
                            {
                                Console.WriteLine("{0}: The specified part of file is" + " already locked.", err.GetType().Name);
                            } //try-catch 
                            break; 

                        case 'U':
                            try
                            {
                                fileStream.Unlock(textLength - 1, byteCount);
                                Console.WriteLine("The specified part of file has been unlocked.");

                            }
                            catch (IOException err)
                            {
                                Console.WriteLine("{0}: The specified part of file is " + "not locked by the current prcess.", err.GetType().Name);
                            }
                            break; 

                        default:
                            consoleInput = 'X';
                            break; 

                    } //switch 

                }

            } //using 



        }

    }

}


Thursday, 12 November 2015

Reading a text file in VB6 and putting the contents into an array

VB6 or Visual Basic 6.0 is not used in many new projects, as it is replaced by .NET. But sometimes you are assigned at work to read and further develop or migrate Legacy code. Let's look at some simple VB6 code. We first read the contents of a file and put each line into a string array. Then we add the items to a listbox control.

Private Sub Command3_Click()

 Dim someFileHandle As Integer
 Dim fileName As String
 Dim someStrings() As String
 
 someFileHandle = FreeFile

 fileName = App.Path + "\fox.txt"
 
 ReDim someStrings(1000) As String

 Open fileName For Input As #someFileHandle
 
 Dim lineNo As Integer
 
 Do Until EOF(someFileHandle)
  Input #someFileHandle, someStrings(lineNo)
  lineNo = lineNo + 1
 Loop
 
 ReDim Preserve someStrings(lineNo - 1) As String
  
 List1.Clear
  
 For x = 0 To lineNo - 1
  List1.AddItem someStrings(x)
 Next x

End Sub


First we get a file handle to the file we want to open. We declare an integer and use the FreeFile method to get a filehandle. We then use the Open function to open a file and assign the file handle. Note the use of the pound sign (#) here. We also declare a large string array, which is one dimensional. We use the ReDim Preserve Method to resize the array to save some memory space and preserve the content. We use the Input Method to put each line into an array element before this is done. Note the use of EOF here. We finally loop through the array and add each array item to a listbox control. So now you should have some basic overview how you can read a file in VB6 into an array structure and loop through its content. How neat is that!