0

I am a beginner in C# programimg and I am looking for a way to make some generics to better work with Entity Framework using multiple databases.

My application was built using only Oracle Database, using all the entities inside my application. Now we have the need to implement SQl Server and MySQL in this application too.

For this I did the following steps:

  • Removed all entities from my main application;
  • Created 3 class libraries, one for each database containing only the models and EF generated classes;
  • Created a 4th class library that contains generic classes to be filled by the objects of each database.

This "generic" class library contain this items for each table:

  • A class with the same name of the table and the same fields (all databases have the same table and field names);
  • An interface that implements base methods;
  • An abstract class that implements the interface methods;
  • A class that inherits from my abstract class for each database;
  • A factory class that creates the required database class using a database type enum.

Below I post a example using my devices table:

Code example

namespace MyApp.Data
{
    internal interface IDevicesDAO
    {
        IEnumerable<Device> GetDevices();
        IEnumerable<Device> GetDevices(int serverId);
        Device GetDeviceById(int deviceId);
    }

    public abstract class DeviceDAO: IDevicesDAO
    {
        public abstract IEnumerable<Business.Device> GetDevices();
        public abstract IEnumerable<Business.Device> GetDevices(int serverId);
        public abstract Business.Device GetDeviceById(int deviceId);

        protected  abstract IEnumerable<Business.Device> ListDevice(int code);
    }

    internal static class DeviceDAO_Factory
    {
        public static DeviceDAO Create(DatabaseTypeEnum databaseType)
        {
            switch (databaseType)
            {
                case DatabaseTypeEnum.Oracle:
                    return new DeviceDAO_Oracle();

                default:
                    return null;
            }
        }
    }

    class DeviceDAO_Oracle: DeviceDAO
    {
        public override IEnumerable<Device> GetDevices()
        {
            return ListDevice(0);
        }

        public override IEnumerable<Device> GetDevices(int serverId)
        {
            return ListDevice(serverId);
        }

        public override Device GetDeviceById(int deviceId)
        {
            OracleContext db = new OracleContext();

            try
            {
                DEVICE loaded = db.DEVICES.Where(d => d.DEVICEID == deviceId).FirstOrDefault();

                if (loaded != null)
                {
                    Device loaDevice = FillDevice(loaded);
                    return loaDevice;
                }
                else
                {
                    return null;
                }
            }
            finally
            {
                db.Dispose();    
            }
        }

        protected override IEnumerable<Device> ListDevice(int code)
        {
            OracleContext db = new OracleContext();

            try
            {
                List<DEVICE> devicelList;
                List<Device> resultList;

                if (code == 0)
                    devicelList = db.DEVICES.Where(d => d.SERVERID == code).ToList();
                else
                    devicelList = db.DEVICES.ToList();

                if (devicelList != null)
                {
                    resultList = new List<Device>();

                    foreach (DEVICE item in devicelList)
                    {
                        Device newDevice = FillDevice(item);
                        resultList.Add(newDevice);
                    }

                    return resultList;
                }
                else
                {
                    return null;
                }
            }
            finally
            {
                db.Dispose();    
            }
        }

        private Device FillDevice(DEVICE item)
        {
            Device current = new Device();

            current.Serverid = item.SERVERID;
            current.Deviceid = item.DEVICEID;
            current.Description = item.DESCRIPTION;
            current.Ipaddress = item.IPADDRESS;
            current.Shots = item.SHOTS;
            current.Matrixnumber = item.MATRIXNUMBER;
            current.Shottime = item.SHOTTIME;
            current.Imageresize = item.IMAGERESIZE;
            current.Imagewidth = item.IMAGEWIDTH;
            current.Imageheight = item.IMAGEHEIGHT;
            current.Devicetype = item.DEVICETYPE;
            current.Devicegroup = item.DEVICEGROUP;
            current.Devicetag = item.DEVICETAG;
            current.Frameinterval = item.FRAMEINTERVAL;
            current.Delaytime = item.DELAYTIME;
            current.Eventinput = item.EVENTINPUT;
            current.Accesspointid = item.ACCESSPOINTID;
            current.Username = item.USERNAME;
            current.Password = item.PASSWORD;
            current.Defaultencoder = item.DEFAULTENCODER;
            current.Isactive = item.ISACTIVE;
            current.Stream = item.STREAM;
            current.Uriaddress = item.URIADDRESS;
            current.Devicesectionid = item.DEVICESECTIONID;
            current.Userid = item.USERID;
            current.Lastupdate = item.LASTUPDATE;
            current.Framerate = item.FRAMERATE;
            current.Initializedevice = item.INITIALIZEDEVICE;
            current.Serviceid = item.SERVICEID;
            current.Insertdelay = item.INSERTDELAY;
            current.Plateposition = item.PLATEPOSITION;
            current.Biosid = item.BIOSID;
            current.Lasttimeactive = item.LASTTIMEACTIVE;
            current.Status = item.STATUS;
            current.Selectedprofiletoken = item.SELECTEDPROFILETOKEN;
            current.Detectionsensibility = item.DETECTIONSENSIBILITY;
            current.OnvifPort = item.ONVIF_PORT;
            current.Nvraddress = item.NVRADDRESS;

            return current;
        }
    }
}

My question is:

See the Oracle class? If I implement SQL Server and MySQL I will have to create 2 more classes with the same code because there are different contexts and differnt table objects (even the objects having the same name and field in different contexts.

I am really not liking this pratice and guess if is that a way to create generics or commom bases to implement all this in a cleaner way.

Sorry evebody for the long post. I tried to be as specific as possible! Sorry for the bad english too :)

Any help will be thankful!

Thanks!

Lucas Neves
  • 59
  • 1
  • 5
  • 1
    In a perfect world you should be able to connect the same context to different database brands, simply by changing the connection string, as long as the db schema is identical. Did you try that? The only thing is: you may experience (not) subtle differences between query providers (i.e. the part that translates C# to SQL). – Gert Arnold Jul 27 '17 at 12:31
  • Yes, I tried your sugestion, but did not worked for me. I had the following inner exception from VS: ================= InnerException: System.Data.SqlClient.SqlException HResult=-2146232060 Message=Invalid object name 'IMAGESEC_VISITOR.PERSON'. Source=.Net SqlClient Data Provider ErrorCode=-2146232060 Class=16 LineNumber=1 Number=208 Procedure="" Server=192.168.2.43 State=1 StackTrace: ========================== Both database and table names are correct. – Lucas Neves Jul 27 '17 at 13:20
  • Hard to tell what's going on here without seeing the context + mappings and the database schema. Still, using one context is the preferred approach. I think you should ask another question focusing on yow to do that, taking this `IMAGESEC_VISITOR.PERSON` table + class as an example. – Gert Arnold Jul 28 '17 at 07:21
  • Another thing is that this DAO pattern doesn't match nicely with EF's repository/Unit of Work pattern. DAOs make it almost impossible to work transactionally with complex object graphs which is exactly the power of EF. Using `DbSet`s directly, without this DAO layer, makes the architecture much thinner so any replication required to target multiple db brands is less costly. – Gert Arnold Jul 28 '17 at 07:24

0 Answers0