Saturday, December 29, 2012

ORM Magic–Importing from any datasource

This post will be on how to use the approach described in Fast prototyping requires an initial data import mechanism with Excel as input source. The technic is based on System.Data.DataSet class and can be applied to any type of input source!

Thanks to your reports and of course Slava’s help (XPO guru), XVideoRental importing mechanism has been improved a lot and now is faster, has notification events and is decoupled from XAF’s TypesInfo system. This makes it possible to simply copy the ImportData.cs file found in Common.Win project and use it in non XAF solutions!

In previous version this importing mechanism worked only when matching in types of input and output members. This means that if my output Oid property was a System.Guid then input should be of the same type. Now we have workaround this minor issue. If conversion is possible it will be done automatically without the need of any configuration or extra coding!

To better design, support, extend and describe the importing mechanism I used Mspec a functional testing framework and I open source the specifications in our community project eXpandFramework. These follow bellow,

MemberMapper, When Class Has a flag that includes all members
» should collect all members that belong to the class
» should not collect any base class member
» should create new members for each one of them

MemberMapper, When class does not have a flag that includes all ownmembers
» should not create members for those not marked with the attribute
» should create members and name them according to the attribute data
» should create a key property if not included in the conficuration

MemberMapper, When class attribute has data for base members
» should create and name them according to the attribute data
» should map their attributes

MemberMapper, When class is marked to include all member but member is marked seperately
» should use the member marking

MemberMapper, When mapping a referenced member
» should create a member with a dynamic type ownwer

MemberMapper, When reference type is not includedIN the configuration
» should create non reference member

ClassMapper, When creating dynamic classes
» should Create Classes only for the ones that have a marking attribute
» should name the classes taking data from marking attribute

ClassMapper, When class has many to many collection marked for importing
» should create intermediate classes
» should create an auto genareted key for this class
» should create 2 columns with names taken from the marked attribute

DictionaryMapper, When is mapping a dictionary
» should map all marked objects

InitDataImporter, When importing an object
» should create a new output object
» should assign all mapped properties

InitDataImporter, When input membertype is different than output
» should convert the value when simple type
» should convert the value when reference type


21 passed, 0 failed, 0 skipped, took 1.61 seconds (Machine.Specifications 0.5.2-98b543c).

The above specifications are evaluated with every eXpand build and you can see them in eXpand’s build server. Take a quick look at their code located in github to see how easy it is to write them (http://goo.gl/TNv4d).

Now lets see how to use our magic XPO ORM to import into the real world business domain like the one of our XVideoRental demo,

image

 

For the sake of complexity the input source will be a list of excel files and not just a simple Excel file with many sheets.

image

XPO supports a DataStore provider which is based on DataSet. So, first we fill a DataSet with the excel files and for this I will use some DataSet extension methods I contributed to eXpand (see http://goo.gl/TF26g)

static DataSet DataSet() {

    var dataSet = new DataSet();

 

    dataSet.ImportExcelXLS(new[]{

        "Customer", "Receipt", "Company", "CompanyType", "Country", "Employee", "Language", "Movie", "MovieArtist",

        "MovieArtistLine", "MovieCategory", "MovieCategoryPrice", "MovieCompany", "MovieItem",

        "MovieMovies_CountryCountries", "MoviePicture","Person","Artist","ArtistPicture","Rent"

    });

 

    return dataSet;

}

 

Now we are ready to create a UnitOfWork with this DataSet as DataStore like,

 

var inputUnitOfWork = new UnitOfWork(new SimpleDataLayer(new DataSetDataStore(DataSet(), AutoCreateOption.None)));

 

and finally call the Import method of the InitDataImporter class as shown bellow

 

var initDataImporter = new InitDataImporter();

            var unitOfWork = OutputUnitOfWork();

            var inputUnitOfWork = new UnitOfWork(new SimpleDataLayer(new DataSetDataStore(DataSet(), AutoCreateOption.None)));

            initDataImporter.Import(() => new UnitOfWork(unitOfWork.ObjectLayer), () => new UnitOfWork(inputUnitOfWork.ObjectLayer));

This simple, however powerful technic can be applied to any type of input source as long as you are able to fill a DataSet!

You can download a sample project was created with v12.2.5 of our Suite from Importer.Console.

Happy New Year to everybody!

Subscribe to XAF feed
Subscribe to community feed

DiggIt!

0 comments:

Post a Comment