This is a migrated thread and some comments may be shown as answers.

Fluent Metadata Source and Inheritance

9 Answers 234 Views
Data Access Free Edition
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Abimael
Top achievements
Rank 1
Abimael asked on 10 Jan 2011, 04:46 AM
Hello there:

I'm trying to implement inheritance with multiple fluent metadata source, using one fluent metadata source as a base for another fluent metadata. I'll put some samples to illustrate my idea.

This code is for the base clases:
public abstract class BaseEntity
{
    public Int32 Id { get; set; }
}
 
public abstract class AuditEntity : BaseEntity
{
    public Int32 CreatedByUserId { get; set; }
    public DateTime CreatedOnDate { get; set; }
    public Int32 LastModifiedByUserId { get; set; }
    public DateTime LastModifiedOnDate { get; set; }
}
 
public abstract class EnableEntity : BaseEntity
{
    public Boolean Enabled { get; set; }
}
 
public abstract class AuditEnableEntity : AuditEntity
{
    public Boolean Enabled { get; set; }
}
 
public class BaseEntitiesMetadataSource : FluentMetadataSource
{
    public BaseEntitiesMetadataSource()
        : base()
    {
    }
 
    public BaseEntitiesMetadataSource(AggregationOptions aggregationOptions)
        : base(aggregationOptions)
    {
    }
 
    public BaseEntitiesMetadataSource(MetadataContainer metadataContainer)
        : base(metadataContainer)
    {
    }
 
    public BaseEntitiesMetadataSource(MetadataContainer metadataContainer, AggregationOptions aggregationOptions)
        : base(metadataContainer, aggregationOptions)
    {
    }
 
    protected override IList<MappingConfiguration> PrepareMapping()
    {
        IList<MappingConfiguration> res = new List<MappingConfiguration>();
 
        MappingConfiguration<BaseEntity> bec = new MappingConfiguration<BaseEntity>();
        bec.MapType().Inheritance(InheritanceStrategy.Vertical).ToTable("BaseEntity");
        bec.HasProperty(x => x.Id).IsIdentity(KeyGenerator.Autoinc);
        bec.FieldNamingRules.AddPrefix = "_";
 
        MappingConfiguration<AuditEntity> baec = new MappingConfiguration<AuditEntity>();
        baec.MapType().Inheritance(InheritanceStrategy.Vertical).ToTable("AuditEntity");
        baec.FieldNamingRules.AddPrefix = "_";
 
        MappingConfiguration<EnableEntity> beec = new MappingConfiguration<EnableEntity>();
        beec.MapType().Inheritance(InheritanceStrategy.Vertical).ToTable("EnableEntity");
        beec.FieldNamingRules.AddPrefix = "_";
 
        MappingConfiguration<AuditEnableEntity> baeec = new MappingConfiguration<AuditEnableEntity>();
        baeec.MapType().Inheritance(InheritanceStrategy.Vertical).ToTable("AuditEnableEntity");
        baeec.FieldNamingRules.AddPrefix = "_";
 
        res.Add(bec);
        res.Add(baec);
        res.Add(beec);
        res.Add(baeec);
 
        return res;
    }
}

And this is for the final classes:
public class Application : AuditEnableEntity
{
    public Guid Guid { get; set; }
    public String Name { get; set; }
    public String Description { get; set; }
}
 
public class EntitiesMetadataSource : BaseEntitiesMetadataSource
{
    public EntitiesMetadataSource()
        : base()
    {
         
    }
 
    public EntitiesMetadataSource(AggregationOptions aggregationOptions)
        : base(aggregationOptions)
    {
    }
 
    public EntitiesMetadataSource(MetadataContainer metadataContainer)
        : base(metadataContainer)
    {
    }
 
    public EntitiesMetadataSource(MetadataContainer metadataContainer, AggregationOptions aggregationOptions)
        : base(metadataContainer, aggregationOptions)
    {
    }
 
    protected override IList<MappingConfiguration> PrepareMapping()
    {
        IList<MappingConfiguration> res = new List<MappingConfiguration>();
 
        MappingConfiguration<Application> ac = new MappingConfiguration<Application>();
        ac.MapType().Inheritance(InheritanceStrategy.Vertical).ToTable("Application");
        ac.FieldNamingRules.AddPrefix = "_";
 
        res.Add(ac);
 
        return res;
    }
}
 
public class MangauAppsContext : OpenAccessContext
{
    private static string connectionStringName = "MangauAppsTest";
         
    private static BackendConfiguration backend = GetBackendConfiguration();
         
    private static MetadataSource metadataSource = new AggregateMetadataSource(new BaseEntitiesMetadataSource(), new EntitiesMetadataSource(), AggregationOptions.Immediate);
 
    public MangauAppsContext()
        :base(connectionStringName, backend, metadataSource)
    { }
     
    public MangauAppsContext(string connection)
        :base(connection, backend, metadataSource)
    { }
 
    public MangauAppsContext(BackendConfiguration backendConfiguration)
        :base(connectionStringName, backendConfiguration, metadataSource)
    { }
         
    public MangauAppsContext(string connection, BackendConfiguration backendConfiguration)
        :base(connection, backendConfiguration, metadataSource)
    { }
         
    public IQueryable<Application> Applications
    {
        get
        {
            return this.GetAll<Application>();
        }
    }
 
    public static BackendConfiguration GetBackendConfiguration()
    {
        BackendConfiguration backend = new BackendConfiguration();
        backend.Backend = "mssql";
        return backend;
    }
}

Well, the class library compiles without errors, but, when I create the database structure, only the tables for the base classes are mapped with the dessired relations to each other, and the table for the Application entity is mapped like if there is no inheritance on it, ad only the fields on the Application class are created the other fields of the base classes are ignored.

This image show the generated database tables for this example.
 OpenAccess Database Example

I want the Application table to be created with a relation to the AuditEnableEntity, like the AuditEnableEntity table has a relation to the AuditEntity table.

How can I do that using multiple fluent metadata sources? I need to do that for a project that will have a base tables and extent the data base with aditional tables using the base classes.

I hope that I explained well and that you understand my question.

Thanks for your help in advance.

Abimael Ordonez.

9 Answers, 1 is accepted

Sort by
0
Serge
Telerik team
answered on 11 Jan 2011, 03:06 PM
Hello Abimael,

 First of all I would like to point out that if all the classes are in one project there is absolutely no need for defining two metadata sources. However if this is the case in order for the aggregate metadata source to correctly combine two models they should have been created with the AggregationOptions.Late option. This is a parameter that is passed to the custom metadata sources that you have created. It basically means that in the models created custom artefacts will be left out that will help later on when association between models are resolved. 

Also I have noticed that your setup might not be entirely correct. When using vertical mapping for inheritance you should only mark the derived classes as vertical, the base class should not be marked with Inheritance(InheritanceStrategy.Vertical). 

I hope this proves to be helpful, however if you face further trouble make sure to let us know.

Kind regards,
Serge
the Telerik team
Accelerate your learning with industry's first Telerik OpenAccess ORM SDK. Download today.
0
Abimael
Top achievements
Rank 1
answered on 11 Jan 2011, 09:35 PM
Hello again:

I aleady tryed with the AggregationOptions.Late with the same result, I tryed removing the vertical inheritance definition for the base classes too, but removing that, all the base classes are on one table, but the Application table is created with the same problem. I will try defining the derived classes on separate projects, and let you know the results.

Thanks and best regards.

Abimael Ordonez.
0
Serge
Telerik team
answered on 12 Jan 2011, 09:56 AM
Hi Abimael,

 I have taken the liberty of modifying you code a little in order to show you what needs to be modified. Please notice how I have added the AggregationOption.Late to the fluent metadata context constructors and not the aggregation one. 

I have attached the project I used for testing this. Please note that I you are planning on keeping all of the classes in one project I suggest using a single metadata source rather than merging multiple with the AggregateMetadataSource.

I hope this is helpful. 

All the best,
Serge
the Telerik team
Accelerate your learning with industry's first Telerik OpenAccess ORM SDK. Download today.
0
Abimael
Top achievements
Rank 1
answered on 12 Jan 2011, 09:41 PM
Hi:

That works pefect, thats exactly what I want to do. This is not a final project, it was a proof of concept, I want to make a class library containing "base metadata" en use it on derived projects for make new ones or extend existing ones. The final base classes will be a little diferent that that, I only want to test if I can make that thing with OpenAccess, and I see that I can.

Thank you very much, and any further help I will contact you again.

Abimael Ordonez.
0
Abimael
Top achievements
Rank 1
answered on 17 Jan 2011, 09:26 AM
Hello there:

I have this code:
public class TestConfBase
{
    public String Name { get; set; }
    public Int64 Cantidad { get; set; }
}
 
public class TestConfChild : TestConfBase
{
    public TestConfChild()
        : base()
    {
        Prueba = Guid.Empty;
    }
 
    public Guid Prueba { get; set; }
}
 
public class Application : AuditEnableEntity
{
    public Guid Guid { get; set; }
    public String Name { get; set; }
    public String Description { get; set; }
 
    public TestConfBase TestConf { get; set; }
}

I want to Serialize to Blob the field TestConf on the Application class, how can I do that with the Fluent API?

Thanks.

AO.
0
Serge
Telerik team
answered on 19 Jan 2011, 10:57 AM
Hello Abimael,

 Currently there is no way to mark properties that have to be serialized to blob using the Fluent Mapping API. However based on your suggestion we will surely be adding this functionality in the next release. A workaround would be to override the CreateModel method of the FluentMetadataSource and in it find the desired persistent type, and it's property (the collection Members) they are listed as MetaMembers but you can cast some of them to MetaPrimitiveMember and set it's serialized to blob property to true. 

However from your configuration TestConfBase look like another persistent type and should not be serialized to blob but rather just persisted. 

I hope this is helpful. Please make sure to let us know if you face further trouble. 

Best wishes,
Serge
the Telerik team
Accelerate your learning with industry's first Telerik OpenAccess ORM SDK. Download today.
0
Abimael
Top achievements
Rank 1
answered on 19 Jan 2011, 11:59 AM
Hi again:

The TestConfBase will be a base class for multiple derived classes that will have diferent properties, and I need that all of the derived classes be saved on the same table. Is like serializing it to a XML string and store it on a nvarchar(MAX) (SQL Server), but on a varbinary(MAX) instead. I want to make a plugin system that will have a lot of diferent plugins, each one with its own configuration properties, but sharing some of them. I'The system will have more than 30 diferent plugins, and I dont want to make 30 tables. The TestConfBase property will be edited with a PropetyGrid like control (on WPF, DotNetNuke and a linux desktop). The Application class will not be the only one with a serialized property like this, there will be some other persisted classes like that. Thats the reason that I whant a form to serialize a property (either to a BLOB file as binary data or to a nvarchar(MAX) as a XML String) and keep the table count of the system not too high.

I hope that you understand my point, and I will try your suggestion, but it will be so useful that the OpenAccess ORM has a property or something to mark a property as serialized.

Thanks a lot, and I'll contact you if I need further help.

AO.
0
Abimael
Top achievements
Rank 1
answered on 23 Jan 2011, 04:45 AM
Hi again:

I tryed with the sugestion of overriding the CreateModel method, but the Member type for the TestConf property cant be casted to MetaPrimitiveMember. Can you give an code example of how to define the SerializeToBlob attribute??

Thanks a lot for your help.

AO.
0
Serge
Telerik team
answered on 24 Jan 2011, 11:36 AM
Hello Abimael,

Unfortunately Telerik OpenAccess ORM does not allow for you to serialize to blob persistent objects. You cannot cast the member to MetaPrimitiveMember because it is actually a MetaNavigationalMember.

However, it is quite easy to persist all of the classes that take part in the hierarchy in one table, you just have to mark the derived classes with flat inheritance, as I guess you have probably already found out.

Please elaborate a bit more if this is your case or is there something else you want to achieve. 

All the best,
Serge
the Telerik team
Accelerate your learning with industry's first Telerik OpenAccess ORM SDK. Download today.
Tags
Data Access Free Edition
Asked by
Abimael
Top achievements
Rank 1
Answers by
Serge
Telerik team
Abimael
Top achievements
Rank 1
Share this question
or